blob: 8cc94444c9d3c25cf12ffc1dda0314b72fff7069 [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>
Arend van Spriel5b435de2011-10-05 13:19:03 +020021#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020022#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023
24#include <brcmu_utils.h>
25#include <defs.h>
26#include <brcmu_wifi.h>
27#include "dhd.h"
Arend van Spriel16886732012-12-05 15:26:04 +010028#include "dhd_dbg.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020029#include "tracepoint.h"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010030#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010031#include "p2p.h"
Piotr Haber61730d42013-04-23 12:53:12 +020032#include "btcoex.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020033#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070034#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020035
Arend van Spriele5806072012-09-19 22:21:08 +020036#define BRCMF_SCAN_IE_LEN_MAX 2048
37#define BRCMF_PNO_VERSION 2
38#define BRCMF_PNO_TIME 30
39#define BRCMF_PNO_REPEAT 4
40#define BRCMF_PNO_FREQ_EXPO_MAX 3
41#define BRCMF_PNO_MAX_PFN_COUNT 16
42#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
43#define BRCMF_PNO_HIDDEN_BIT 2
44#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
45#define BRCMF_PNO_SCAN_COMPLETE 1
46#define BRCMF_PNO_SCAN_INCOMPLETE 0
47
Arend van Spriel9f440b72013-02-08 15:53:36 +010048#define BRCMF_IFACE_MAX_CNT 3
Arend van Spriel3eacf862012-10-22 13:55:30 -070049
Hante Meuleman1a873342012-09-27 14:17:54 +020050#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
51#define WPA_OUI_TYPE 1
52#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
53#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010054#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020055
56#define VS_IE_FIXED_HDR_LEN 6
57#define WPA_IE_VERSION_LEN 2
58#define WPA_IE_MIN_OUI_LEN 4
59#define WPA_IE_SUITE_COUNT_LEN 2
60
61#define WPA_CIPHER_NONE 0 /* None */
62#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
63#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
64#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
65#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
66
67#define RSN_AKM_NONE 0 /* None (IBSS) */
68#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
69#define RSN_AKM_PSK 2 /* Pre-shared Key */
70#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
71#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
72
73#define VNDR_IE_CMD_LEN 4 /* length of the set command
74 * string :"add", "del" (+ NUL)
75 */
76#define VNDR_IE_COUNT_OFFSET 4
77#define VNDR_IE_PKTFLAG_OFFSET 8
78#define VNDR_IE_VSIE_OFFSET 12
79#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010080#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020081
82#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
83#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020084
Hante Meuleman89286dc2013-02-08 15:53:46 +010085#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
86#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
87#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
88
Arend van Spriel5b435de2011-10-05 13:19:03 +020089#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
90 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
91
Arend van Sprielce81e312012-10-22 13:55:37 -070092static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020093{
Arend van Sprielc1179032012-10-22 13:55:33 -070094 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +010095 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
96 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +020097 return false;
98 }
99 return true;
100}
101
102#define CHAN2G(_channel, _freq, _flags) { \
103 .band = IEEE80211_BAND_2GHZ, \
104 .center_freq = (_freq), \
105 .hw_value = (_channel), \
106 .flags = (_flags), \
107 .max_antenna_gain = 0, \
108 .max_power = 30, \
109}
110
111#define CHAN5G(_channel, _flags) { \
112 .band = IEEE80211_BAND_5GHZ, \
113 .center_freq = 5000 + (5 * (_channel)), \
114 .hw_value = (_channel), \
115 .flags = (_flags), \
116 .max_antenna_gain = 0, \
117 .max_power = 30, \
118}
119
120#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
121#define RATETAB_ENT(_rateid, _flags) \
122 { \
123 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
124 .hw_value = (_rateid), \
125 .flags = (_flags), \
126 }
127
128static struct ieee80211_rate __wl_rates[] = {
129 RATETAB_ENT(BRCM_RATE_1M, 0),
130 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
131 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
132 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
133 RATETAB_ENT(BRCM_RATE_6M, 0),
134 RATETAB_ENT(BRCM_RATE_9M, 0),
135 RATETAB_ENT(BRCM_RATE_12M, 0),
136 RATETAB_ENT(BRCM_RATE_18M, 0),
137 RATETAB_ENT(BRCM_RATE_24M, 0),
138 RATETAB_ENT(BRCM_RATE_36M, 0),
139 RATETAB_ENT(BRCM_RATE_48M, 0),
140 RATETAB_ENT(BRCM_RATE_54M, 0),
141};
142
143#define wl_a_rates (__wl_rates + 4)
144#define wl_a_rates_size 8
145#define wl_g_rates (__wl_rates + 0)
146#define wl_g_rates_size 12
147
148static struct ieee80211_channel __wl_2ghz_channels[] = {
149 CHAN2G(1, 2412, 0),
150 CHAN2G(2, 2417, 0),
151 CHAN2G(3, 2422, 0),
152 CHAN2G(4, 2427, 0),
153 CHAN2G(5, 2432, 0),
154 CHAN2G(6, 2437, 0),
155 CHAN2G(7, 2442, 0),
156 CHAN2G(8, 2447, 0),
157 CHAN2G(9, 2452, 0),
158 CHAN2G(10, 2457, 0),
159 CHAN2G(11, 2462, 0),
160 CHAN2G(12, 2467, 0),
161 CHAN2G(13, 2472, 0),
162 CHAN2G(14, 2484, 0),
163};
164
165static struct ieee80211_channel __wl_5ghz_a_channels[] = {
166 CHAN5G(34, 0), CHAN5G(36, 0),
167 CHAN5G(38, 0), CHAN5G(40, 0),
168 CHAN5G(42, 0), CHAN5G(44, 0),
169 CHAN5G(46, 0), CHAN5G(48, 0),
170 CHAN5G(52, 0), CHAN5G(56, 0),
171 CHAN5G(60, 0), CHAN5G(64, 0),
172 CHAN5G(100, 0), CHAN5G(104, 0),
173 CHAN5G(108, 0), CHAN5G(112, 0),
174 CHAN5G(116, 0), CHAN5G(120, 0),
175 CHAN5G(124, 0), CHAN5G(128, 0),
176 CHAN5G(132, 0), CHAN5G(136, 0),
177 CHAN5G(140, 0), CHAN5G(149, 0),
178 CHAN5G(153, 0), CHAN5G(157, 0),
179 CHAN5G(161, 0), CHAN5G(165, 0),
180 CHAN5G(184, 0), CHAN5G(188, 0),
181 CHAN5G(192, 0), CHAN5G(196, 0),
182 CHAN5G(200, 0), CHAN5G(204, 0),
183 CHAN5G(208, 0), CHAN5G(212, 0),
184 CHAN5G(216, 0),
185};
186
Arend van Spriel5b435de2011-10-05 13:19:03 +0200187static struct ieee80211_supported_band __wl_band_2ghz = {
188 .band = IEEE80211_BAND_2GHZ,
189 .channels = __wl_2ghz_channels,
190 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
191 .bitrates = wl_g_rates,
192 .n_bitrates = wl_g_rates_size,
193};
194
195static struct ieee80211_supported_band __wl_band_5ghz_a = {
196 .band = IEEE80211_BAND_5GHZ,
197 .channels = __wl_5ghz_a_channels,
198 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
199 .bitrates = wl_a_rates,
200 .n_bitrates = wl_a_rates_size,
201};
202
Hante Meulemand48200b2013-04-03 12:40:29 +0200203/* This is to override regulatory domains defined in cfg80211 module (reg.c)
204 * By default world regulatory domain defined in reg.c puts the flags
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200205 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
206 * With respect to these flags, wpa_supplicant doesn't * start p2p
207 * operations on 5GHz channels. All the changes in world regulatory
Hante Meulemand48200b2013-04-03 12:40:29 +0200208 * domain are to be done here.
209 */
210static const struct ieee80211_regdomain brcmf_regdom = {
211 .n_reg_rules = 4,
212 .alpha2 = "99",
213 .reg_rules = {
214 /* IEEE 802.11b/g, channels 1..11 */
215 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
216 /* If any */
217 /* IEEE 802.11 channel 14 - Only JP enables
218 * this and for 802.11b only
219 */
220 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
221 /* IEEE 802.11a, channel 36..64 */
222 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
223 /* IEEE 802.11a, channel 100..165 */
224 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200225};
226
227static const u32 __wl_cipher_suites[] = {
228 WLAN_CIPHER_SUITE_WEP40,
229 WLAN_CIPHER_SUITE_WEP104,
230 WLAN_CIPHER_SUITE_TKIP,
231 WLAN_CIPHER_SUITE_CCMP,
232 WLAN_CIPHER_SUITE_AES_CMAC,
233};
234
Hante Meuleman1a873342012-09-27 14:17:54 +0200235/* Vendor specific ie. id = 221, oui and type defines exact ie */
236struct brcmf_vs_tlv {
237 u8 id;
238 u8 len;
239 u8 oui[3];
240 u8 oui_type;
241};
242
243struct parsed_vndr_ie_info {
244 u8 *ie_ptr;
245 u32 ie_len; /* total length including id & length field */
246 struct brcmf_vs_tlv vndrie;
247};
248
249struct parsed_vndr_ies {
250 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100251 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200252};
253
Alwin Beukersef6ac172011-10-12 20:51:26 +0200254/* Quarter dBm units to mW
255 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
256 * Table is offset so the last entry is largest mW value that fits in
257 * a u16.
258 */
259
260#define QDBM_OFFSET 153 /* Offset for first entry */
261#define QDBM_TABLE_LEN 40 /* Table size */
262
263/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
264 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
265 */
266#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
267
268/* Largest mW value that will round down to the last table entry,
269 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
270 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
271 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
272 */
273#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
274
275static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
276/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
277/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
278/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
279/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
280/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
281/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
282};
283
284static u16 brcmf_qdbm_to_mw(u8 qdbm)
285{
286 uint factor = 1;
287 int idx = qdbm - QDBM_OFFSET;
288
289 if (idx >= QDBM_TABLE_LEN)
290 /* clamp to max u16 mW value */
291 return 0xFFFF;
292
293 /* scale the qdBm index up to the range of the table 0-40
294 * where an offset of 40 qdBm equals a factor of 10 mW.
295 */
296 while (idx < 0) {
297 idx += 40;
298 factor *= 10;
299 }
300
301 /* return the mW value scaled down to the correct factor of 10,
302 * adding in factor/2 to get proper rounding.
303 */
304 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
305}
306
307static u8 brcmf_mw_to_qdbm(u16 mw)
308{
309 u8 qdbm;
310 int offset;
311 uint mw_uint = mw;
312 uint boundary;
313
314 /* handle boundary case */
315 if (mw_uint <= 1)
316 return 0;
317
318 offset = QDBM_OFFSET;
319
320 /* move mw into the range of the table */
321 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
322 mw_uint *= 10;
323 offset -= 40;
324 }
325
326 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
327 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
328 nqdBm_to_mW_map[qdbm]) / 2;
329 if (mw_uint < boundary)
330 break;
331 }
332
333 qdbm += (u8) offset;
334
335 return qdbm;
336}
337
Franky Lin83cf17a2013-04-11 13:28:50 +0200338u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
339 struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700340{
Franky Lin83cf17a2013-04-11 13:28:50 +0200341 struct brcmu_chan ch_inf;
Arend van Spriel6e186162012-10-22 10:36:22 -0700342
Franky Lin83cf17a2013-04-11 13:28:50 +0200343 ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
344 ch_inf.bw = BRCMU_CHAN_BW_20;
345 d11inf->encchspec(&ch_inf);
Arend van Spriel6e186162012-10-22 10:36:22 -0700346
Franky Lin83cf17a2013-04-11 13:28:50 +0200347 return ch_inf.chspec;
Arend van Spriel6e186162012-10-22 10:36:22 -0700348}
349
Hante Meuleman89286dc2013-02-08 15:53:46 +0100350/* Traverse a string of 1-byte tag/1-byte length/variable-length value
351 * triples, returning a pointer to the substring whose first element
352 * matches tag
353 */
354struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
355{
356 struct brcmf_tlv *elt;
357 int totlen;
358
359 elt = (struct brcmf_tlv *)buf;
360 totlen = buflen;
361
362 /* find tagged parameter */
363 while (totlen >= TLV_HDR_LEN) {
364 int len = elt->len;
365
366 /* validate remaining totlen */
367 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
368 return elt;
369
370 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
371 totlen -= (len + TLV_HDR_LEN);
372 }
373
374 return NULL;
375}
376
377/* Is any of the tlvs the expected entry? If
378 * not update the tlvs buffer pointer/length.
379 */
380static bool
381brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
382 u8 *oui, u32 oui_len, u8 type)
383{
384 /* If the contents match the OUI and the type */
385 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
386 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
387 type == ie[TLV_BODY_OFF + oui_len]) {
388 return true;
389 }
390
391 if (tlvs == NULL)
392 return false;
393 /* point to the next ie */
394 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
395 /* calculate the length of the rest of the buffer */
396 *tlvs_len -= (int)(ie - *tlvs);
397 /* update the pointer to the start of the buffer */
398 *tlvs = ie;
399
400 return false;
401}
402
403static struct brcmf_vs_tlv *
404brcmf_find_wpaie(u8 *parse, u32 len)
405{
406 struct brcmf_tlv *ie;
407
408 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
409 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
410 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
411 return (struct brcmf_vs_tlv *)ie;
412 }
413 return NULL;
414}
415
416static struct brcmf_vs_tlv *
417brcmf_find_wpsie(u8 *parse, u32 len)
418{
419 struct brcmf_tlv *ie;
420
421 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
422 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
423 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
424 return (struct brcmf_vs_tlv *)ie;
425 }
426 return NULL;
427}
428
429
Arend van Spriel5b435de2011-10-05 13:19:03 +0200430static void convert_key_from_CPU(struct brcmf_wsec_key *key,
431 struct brcmf_wsec_key_le *key_le)
432{
433 key_le->index = cpu_to_le32(key->index);
434 key_le->len = cpu_to_le32(key->len);
435 key_le->algo = cpu_to_le32(key->algo);
436 key_le->flags = cpu_to_le32(key->flags);
437 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
438 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
439 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
440 memcpy(key_le->data, key->data, sizeof(key->data));
441 memcpy(key_le->ea, key->ea, sizeof(key->ea));
442}
443
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200444static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700445send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200446{
447 int err;
448 struct brcmf_wsec_key_le key_le;
449
450 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200451
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700452 brcmf_netdev_wait_pend8021x(ndev);
453
Arend van Sprielac24be62012-10-22 10:36:23 -0700454 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700455 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200456
Arend van Spriel5b435de2011-10-05 13:19:03 +0200457 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100458 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459 return err;
460}
461
Hante Meulemanb3657452013-05-27 21:09:53 +0200462static s32
463brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
464{
465 s32 err;
466 u32 mode;
467
468 if (enable)
469 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
470 else
471 mode = 0;
472
473 /* Try to set and enable ARP offload feature, this may fail, then it */
474 /* is simply not supported and err 0 will be returned */
475 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
476 if (err) {
477 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
478 mode, err);
479 err = 0;
480 } else {
481 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
482 if (err) {
483 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
484 enable, err);
485 err = 0;
486 } else
487 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
488 enable, mode);
489 }
490
491 return err;
492}
493
Arend van Spriel9f440b72013-02-08 15:53:36 +0100494static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
495 const char *name,
496 enum nl80211_iftype type,
497 u32 *flags,
498 struct vif_params *params)
499{
500 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
501 switch (type) {
502 case NL80211_IFTYPE_ADHOC:
503 case NL80211_IFTYPE_STATION:
504 case NL80211_IFTYPE_AP:
505 case NL80211_IFTYPE_AP_VLAN:
506 case NL80211_IFTYPE_WDS:
507 case NL80211_IFTYPE_MONITOR:
508 case NL80211_IFTYPE_MESH_POINT:
509 return ERR_PTR(-EOPNOTSUPP);
510 case NL80211_IFTYPE_P2P_CLIENT:
511 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200512 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100513 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
514 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100515 default:
516 return ERR_PTR(-EINVAL);
517 }
518}
519
Arend van Sprielf96aa072013-04-05 10:57:48 +0200520void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100521{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100522 s32 err = 0;
523
524 if (check_vif_up(ifp->vif)) {
525 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
526 if (err) {
527 brcmf_err("fail to set mpc\n");
528 return;
529 }
530 brcmf_dbg(INFO, "MPC : %d\n", mpc);
531 }
532}
533
Arend van Spriela0f472a2013-04-05 10:57:49 +0200534s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
535 struct brcmf_if *ifp, bool aborted,
536 bool fw_abort)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100537{
538 struct brcmf_scan_params_le params_le;
539 struct cfg80211_scan_request *scan_request;
540 s32 err = 0;
541
542 brcmf_dbg(SCAN, "Enter\n");
543
544 /* clear scan request, because the FW abort can cause a second call */
545 /* to this functon and might cause a double cfg80211_scan_done */
546 scan_request = cfg->scan_request;
547 cfg->scan_request = NULL;
548
549 if (timer_pending(&cfg->escan_timeout))
550 del_timer_sync(&cfg->escan_timeout);
551
552 if (fw_abort) {
553 /* Do a scan abort to stop the driver's scan engine */
554 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
555 memset(&params_le, 0, sizeof(params_le));
556 memset(params_le.bssid, 0xFF, ETH_ALEN);
557 params_le.bss_type = DOT11_BSSTYPE_ANY;
558 params_le.scan_type = 0;
559 params_le.channel_num = cpu_to_le32(1);
560 params_le.nprobes = cpu_to_le32(1);
561 params_le.active_time = cpu_to_le32(-1);
562 params_le.passive_time = cpu_to_le32(-1);
563 params_le.home_time = cpu_to_le32(-1);
564 /* Scan is aborted by setting channel_list[0] to -1 */
565 params_le.channel_list[0] = cpu_to_le16(-1);
566 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielf96aa072013-04-05 10:57:48 +0200567 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100568 &params_le, sizeof(params_le));
569 if (err)
570 brcmf_err("Scan abort failed\n");
571 }
572 /*
573 * e-scan can be initiated by scheduled scan
574 * which takes precedence.
575 */
576 if (cfg->sched_escan) {
577 brcmf_dbg(SCAN, "scheduled scan completed\n");
578 cfg->sched_escan = false;
579 if (!aborted)
580 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Sprielf96aa072013-04-05 10:57:48 +0200581 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100582 } else if (scan_request) {
583 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
584 aborted ? "Aborted" : "Done");
585 cfg80211_scan_done(scan_request, aborted);
Arend van Sprielf96aa072013-04-05 10:57:48 +0200586 brcmf_set_mpc(ifp, 1);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100587 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100588 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
589 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100590
591 return err;
592}
593
Arend van Spriel9f440b72013-02-08 15:53:36 +0100594static
595int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
596{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100597 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
598 struct net_device *ndev = wdev->netdev;
599
600 /* vif event pending in firmware */
601 if (brcmf_cfg80211_vif_event_armed(cfg))
602 return -EBUSY;
603
604 if (ndev) {
605 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
Arend van Spriela0f472a2013-04-05 10:57:49 +0200606 cfg->escan_info.ifp == netdev_priv(ndev))
607 brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
608 true, true);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100609
610 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
611 }
612
Arend van Spriel9f440b72013-02-08 15:53:36 +0100613 switch (wdev->iftype) {
614 case NL80211_IFTYPE_ADHOC:
615 case NL80211_IFTYPE_STATION:
616 case NL80211_IFTYPE_AP:
617 case NL80211_IFTYPE_AP_VLAN:
618 case NL80211_IFTYPE_WDS:
619 case NL80211_IFTYPE_MONITOR:
620 case NL80211_IFTYPE_MESH_POINT:
621 return -EOPNOTSUPP;
622 case NL80211_IFTYPE_P2P_CLIENT:
623 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel27f10e32013-04-05 10:57:50 +0200624 case NL80211_IFTYPE_P2P_DEVICE:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100625 return brcmf_p2p_del_vif(wiphy, wdev);
626 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel9f440b72013-02-08 15:53:36 +0100627 default:
628 return -EINVAL;
629 }
630 return -EOPNOTSUPP;
631}
632
Arend van Spriel5b435de2011-10-05 13:19:03 +0200633static s32
634brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
635 enum nl80211_iftype type, u32 *flags,
636 struct vif_params *params)
637{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100638 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700639 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100640 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200641 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200642 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200643 s32 err = 0;
644
Arend van Sprield96b8012012-12-05 15:26:02 +0100645 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200646
647 switch (type) {
648 case NL80211_IFTYPE_MONITOR:
649 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100650 brcmf_err("type (%d) : currently we do not support this type\n",
651 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200652 return -EOPNOTSUPP;
653 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100654 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200655 infra = 0;
656 break;
657 case NL80211_IFTYPE_STATION:
Hante Meuleman1bc7c652013-02-08 15:53:56 +0100658 /* Ignore change for p2p IF. Unclear why supplicant does this */
659 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
660 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
661 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
662 /* WAR: It is unexpected to get a change of VIF for P2P
663 * IF, but it happens. The request can not be handled
664 * but returning EPERM causes a crash. Returning 0
665 * without setting ieee80211_ptr->iftype causes trace
666 * (WARN_ON) but it works with wpa_supplicant
667 */
668 return 0;
669 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100670 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200671 infra = 1;
672 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200673 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100674 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100675 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200676 ap = 1;
677 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200678 default:
679 err = -EINVAL;
680 goto done;
681 }
682
Hante Meuleman1a873342012-09-27 14:17:54 +0200683 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100684 if (type == NL80211_IFTYPE_P2P_GO) {
685 brcmf_dbg(INFO, "IF Type = P2P GO\n");
686 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
687 }
688 if (!err) {
689 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
690 brcmf_dbg(INFO, "IF Type = AP\n");
691 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200692 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100693 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200694 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100695 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200696 err = -EAGAIN;
697 goto done;
698 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100699 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
700 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200701 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200702 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200703
704done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100705 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200706
707 return err;
708}
709
Franky Lin83cf17a2013-04-11 13:28:50 +0200710static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
711 struct brcmf_scan_params_le *params_le,
Hante Meulemane756af52012-09-11 21:18:52 +0200712 struct cfg80211_scan_request *request)
713{
714 u32 n_ssids;
715 u32 n_channels;
716 s32 i;
717 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200718 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200719 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200720 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200721
Arend van Sprielba40d162012-10-22 13:55:38 -0700722 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200723 params_le->bss_type = DOT11_BSSTYPE_ANY;
724 params_le->scan_type = 0;
725 params_le->channel_num = 0;
726 params_le->nprobes = cpu_to_le32(-1);
727 params_le->active_time = cpu_to_le32(-1);
728 params_le->passive_time = cpu_to_le32(-1);
729 params_le->home_time = cpu_to_le32(-1);
730 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
731
732 /* if request is null exit so it will be all channel broadcast scan */
733 if (!request)
734 return;
735
736 n_ssids = request->n_ssids;
737 n_channels = request->n_channels;
738 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100739 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
740 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200741 if (n_channels > 0) {
742 for (i = 0; i < n_channels; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +0200743 chanspec = channel_to_chanspec(&cfg->d11inf,
744 request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100745 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
746 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200747 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200748 }
749 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100750 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200751 }
752 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100753 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200754 if (n_ssids > 0) {
755 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
756 n_channels * sizeof(u16);
757 offset = roundup(offset, sizeof(u32));
758 ptr = (char *)params_le + offset;
759 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200760 memset(&ssid_le, 0, sizeof(ssid_le));
761 ssid_le.SSID_len =
762 cpu_to_le32(request->ssids[i].ssid_len);
763 memcpy(ssid_le.SSID, request->ssids[i].ssid,
764 request->ssids[i].ssid_len);
765 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100766 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200767 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100768 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
769 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200770 memcpy(ptr, &ssid_le, sizeof(ssid_le));
771 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200772 }
773 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100774 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200775 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100776 brcmf_dbg(SCAN, "SSID %s len=%d\n",
777 params_le->ssid_le.SSID,
778 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200779 params_le->ssid_le.SSID_len =
780 cpu_to_le32(request->ssids->ssid_len);
781 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
782 request->ssids->ssid_len);
783 }
784 }
785 /* Adding mask to channel numbers */
786 params_le->channel_num =
787 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
788 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
789}
790
791static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200792brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +0200793 struct cfg80211_scan_request *request, u16 action)
794{
795 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
796 offsetof(struct brcmf_escan_params_le, params_le);
797 struct brcmf_escan_params_le *params;
798 s32 err = 0;
799
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100800 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200801
802 if (request != NULL) {
803 /* Allocate space for populating ssids in struct */
804 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
805
806 /* Allocate space for populating ssids in struct */
807 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
808 }
809
810 params = kzalloc(params_size, GFP_KERNEL);
811 if (!params) {
812 err = -ENOMEM;
813 goto exit;
814 }
815 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
Franky Lin83cf17a2013-04-11 13:28:50 +0200816 brcmf_escan_prep(cfg, &params->params_le, request);
Hante Meulemane756af52012-09-11 21:18:52 +0200817 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
818 params->action = cpu_to_le16(action);
819 params->sync_id = cpu_to_le16(0x1234);
820
Arend van Spriela0f472a2013-04-05 10:57:49 +0200821 err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200822 if (err) {
823 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100824 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200825 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100826 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200827 }
828
829 kfree(params);
830exit:
831 return err;
832}
833
834static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200835brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Arend van Spriela0f472a2013-04-05 10:57:49 +0200836 struct brcmf_if *ifp, struct cfg80211_scan_request *request)
Hante Meulemane756af52012-09-11 21:18:52 +0200837{
838 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700839 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200840 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100841 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200842
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100843 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200844 escan->ifp = ifp;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100845 escan->wiphy = wiphy;
846 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700847 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielf96aa072013-04-05 10:57:48 +0200848 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700849 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200850 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100851 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200852 return err;
853 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200854 brcmf_set_mpc(ifp, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200855 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200856 results->version = 0;
857 results->count = 0;
858 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
859
Arend van Spriela0f472a2013-04-05 10:57:49 +0200860 err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200861 if (err)
Arend van Sprielf96aa072013-04-05 10:57:48 +0200862 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200863 return err;
864}
865
866static s32
Arend van Spriela0f472a2013-04-05 10:57:49 +0200867brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
Hante Meulemane756af52012-09-11 21:18:52 +0200868 struct cfg80211_scan_request *request,
869 struct cfg80211_ssid *this_ssid)
870{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200871 struct brcmf_if *ifp = vif->ifp;
872 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meulemane756af52012-09-11 21:18:52 +0200873 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800874 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700875 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200876 bool escan_req;
877 bool spec_scan;
878 s32 err;
879 u32 SSID_len;
880
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100881 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200882
Arend van Sprielc1179032012-10-22 13:55:33 -0700883 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100884 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200885 return -EAGAIN;
886 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700887 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100888 brcmf_err("Scanning being aborted: status (%lu)\n",
889 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200890 return -EAGAIN;
891 }
Arend van Spriel1687eee2013-04-23 12:53:11 +0200892 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
893 brcmf_err("Scanning suppressed: status (%lu)\n",
894 cfg->scan_status);
895 return -EAGAIN;
896 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700897 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100898 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200899 return -EAGAIN;
900 }
901
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100902 /* If scan req comes for p2p0, send it over primary I/F */
Arend van Spriela0f472a2013-04-05 10:57:49 +0200903 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
904 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100905
Hante Meulemane756af52012-09-11 21:18:52 +0200906 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200907 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200908 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
909
910 escan_req = false;
911 if (request) {
912 /* scan bss */
913 ssids = request->ssids;
914 escan_req = true;
915 } else {
916 /* scan in ibss */
917 /* we don't do escan in ibss */
918 ssids = this_ssid;
919 }
920
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200921 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700922 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200923 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100924 cfg->escan_info.run = brcmf_run_escan;
Arend van Spriela0f472a2013-04-05 10:57:49 +0200925 err = brcmf_p2p_scan_prep(wiphy, request, vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100926 if (err)
927 goto scan_out;
928
Arend van Spriela0f472a2013-04-05 10:57:49 +0200929 err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800930 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200931 goto scan_out;
932 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100933 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
934 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200935 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
936 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
937 sr->ssid_le.SSID_len = cpu_to_le32(0);
938 spec_scan = false;
939 if (SSID_len) {
940 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
941 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
942 spec_scan = true;
943 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100944 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200945
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700946 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700947 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700948 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200949 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100950 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200951 goto scan_out;
952 }
Arend van Sprielf96aa072013-04-05 10:57:48 +0200953 brcmf_set_mpc(ifp, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700954 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700955 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200956 if (err) {
957 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100958 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
959 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200960 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100961 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200962
Arend van Sprielf96aa072013-04-05 10:57:48 +0200963 brcmf_set_mpc(ifp, 1);
Hante Meulemane756af52012-09-11 21:18:52 +0200964 goto scan_out;
965 }
966 }
967
968 return 0;
969
970scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700971 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200972 if (timer_pending(&cfg->escan_timeout))
973 del_timer_sync(&cfg->escan_timeout);
974 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200975 return err;
976}
977
Arend van Spriel5b435de2011-10-05 13:19:03 +0200978static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700979brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200980{
Arend van Spriela0f472a2013-04-05 10:57:49 +0200981 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200982 s32 err = 0;
983
Arend van Sprield96b8012012-12-05 15:26:02 +0100984 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriela0f472a2013-04-05 10:57:49 +0200985 vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
986 if (!check_vif_up(vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200987 return -EIO;
988
Arend van Spriela0f472a2013-04-05 10:57:49 +0200989 err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200990
Arend van Spriel5b435de2011-10-05 13:19:03 +0200991 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100992 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200993
Arend van Sprield96b8012012-12-05 15:26:02 +0100994 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200995 return err;
996}
997
998static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
999{
1000 s32 err = 0;
1001
Arend van Sprielac24be62012-10-22 10:36:23 -07001002 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1003 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001004 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001005 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001006
1007 return err;
1008}
1009
1010static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1011{
1012 s32 err = 0;
1013
Arend van Sprielac24be62012-10-22 10:36:23 -07001014 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1015 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001016 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001017 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001018
1019 return err;
1020}
1021
1022static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1023{
1024 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001025 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001026
Arend van Sprielac24be62012-10-22 10:36:23 -07001027 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001028 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001029 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001030 return err;
1031 }
1032 return err;
1033}
1034
1035static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1036{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001037 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1038 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001039 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001040 s32 err = 0;
1041
Arend van Sprield96b8012012-12-05 15:26:02 +01001042 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001043 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001044 return -EIO;
1045
1046 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001047 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1048 cfg->conf->rts_threshold = wiphy->rts_threshold;
1049 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001050 if (!err)
1051 goto done;
1052 }
1053 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001054 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1055 cfg->conf->frag_threshold = wiphy->frag_threshold;
1056 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001057 if (!err)
1058 goto done;
1059 }
1060 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001061 && (cfg->conf->retry_long != wiphy->retry_long)) {
1062 cfg->conf->retry_long = wiphy->retry_long;
1063 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001064 if (!err)
1065 goto done;
1066 }
1067 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001068 && (cfg->conf->retry_short != wiphy->retry_short)) {
1069 cfg->conf->retry_short = wiphy->retry_short;
1070 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001071 if (!err)
1072 goto done;
1073 }
1074
1075done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001076 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001077 return err;
1078}
1079
Arend van Spriel5b435de2011-10-05 13:19:03 +02001080static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1081{
1082 memset(prof, 0, sizeof(*prof));
1083}
1084
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001085static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001086{
Piotr Haber61730d42013-04-23 12:53:12 +02001087 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001088 s32 err = 0;
1089
Arend van Sprield96b8012012-12-05 15:26:02 +01001090 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001091
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001092 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001093 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001094 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001095 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriela538ae32013-07-25 23:01:34 +02001096 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001097 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriela538ae32013-07-25 23:01:34 +02001098 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001099 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001100 cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
1101
Arend van Spriel5b435de2011-10-05 13:19:03 +02001102 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001103 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Piotr Haber61730d42013-04-23 12:53:12 +02001104 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
1105 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
Arend van Sprield96b8012012-12-05 15:26:02 +01001106 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001107}
1108
1109static s32
1110brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1111 struct cfg80211_ibss_params *params)
1112{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001113 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001114 struct brcmf_if *ifp = netdev_priv(ndev);
1115 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001116 struct brcmf_join_params join_params;
1117 size_t join_params_size = 0;
1118 s32 err = 0;
1119 s32 wsec = 0;
1120 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001121 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001122
Arend van Sprield96b8012012-12-05 15:26:02 +01001123 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001124 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001125 return -EIO;
1126
1127 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001128 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001129 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001130 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001131 return -EOPNOTSUPP;
1132 }
1133
Arend van Sprielc1179032012-10-22 13:55:33 -07001134 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001135
1136 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001137 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001138 else
Arend van Spriel16886732012-12-05 15:26:04 +01001139 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001140
Johannes Berg683b6d32012-11-08 21:25:48 +01001141 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001142 brcmf_dbg(CONN, "channel: %d\n",
1143 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001144 else
Arend van Spriel16886732012-12-05 15:26:04 +01001145 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001146
1147 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001148 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001149 else
Arend van Spriel16886732012-12-05 15:26:04 +01001150 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001151
1152 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001153 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001154 else
Arend van Spriel16886732012-12-05 15:26:04 +01001155 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001156
1157 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001158 brcmf_dbg(CONN, "beacon interval: %d\n",
1159 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001160 else
Arend van Spriel16886732012-12-05 15:26:04 +01001161 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001162
1163 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001164 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001165 else
Arend van Spriel16886732012-12-05 15:26:04 +01001166 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001167
1168 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001169 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170 else
Arend van Spriel16886732012-12-05 15:26:04 +01001171 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001172
1173 /* Configure Privacy for starter */
1174 if (params->privacy)
1175 wsec |= WEP_ENABLED;
1176
Arend van Sprielc1179032012-10-22 13:55:33 -07001177 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001178 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001179 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001180 goto done;
1181 }
1182
1183 /* Configure Beacon Interval for starter */
1184 if (params->beacon_interval)
1185 bcnprd = params->beacon_interval;
1186 else
1187 bcnprd = 100;
1188
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001189 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001190 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001191 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001192 goto done;
1193 }
1194
1195 /* Configure required join parameter */
1196 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1197
1198 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001199 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1200 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1201 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1202 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001203 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001204
1205 /* BSSID */
1206 if (params->bssid) {
1207 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1208 join_params_size = sizeof(join_params.ssid_le) +
1209 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001210 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001211 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001212 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001213 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001214 }
1215
Arend van Spriel5b435de2011-10-05 13:19:03 +02001216 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001217 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001218 u32 target_channel;
1219
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001220 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001221 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001222 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001223 if (params->channel_fixed) {
1224 /* adding chanspec */
Franky Lin83cf17a2013-04-11 13:28:50 +02001225 chanspec = channel_to_chanspec(&cfg->d11inf,
1226 params->chandef.chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001227 join_params.params_le.chanspec_list[0] =
1228 cpu_to_le16(chanspec);
1229 join_params.params_le.chanspec_num = cpu_to_le32(1);
1230 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001231 }
1232
1233 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001234 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001235 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001236 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001238 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001239 goto done;
1240 }
1241 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001242 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001243
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001244 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001245
1246
Arend van Sprielc1179032012-10-22 13:55:33 -07001247 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001248 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001249 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001250 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001251 goto done;
1252 }
1253
1254done:
1255 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001256 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001257 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001258 return err;
1259}
1260
1261static s32
1262brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1263{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001264 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001265 s32 err = 0;
1266
Arend van Sprield96b8012012-12-05 15:26:02 +01001267 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001268 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001269 return -EIO;
1270
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001271 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272
Arend van Sprield96b8012012-12-05 15:26:02 +01001273 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001274
1275 return err;
1276}
1277
1278static s32 brcmf_set_wpa_version(struct net_device *ndev,
1279 struct cfg80211_connect_params *sme)
1280{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001281 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001282 struct brcmf_cfg80211_security *sec;
1283 s32 val = 0;
1284 s32 err = 0;
1285
1286 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1287 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1288 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1289 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1290 else
1291 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001292 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001293 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001294 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001295 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001296 return err;
1297 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001298 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001299 sec->wpa_versions = sme->crypto.wpa_versions;
1300 return err;
1301}
1302
1303static s32 brcmf_set_auth_type(struct net_device *ndev,
1304 struct cfg80211_connect_params *sme)
1305{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001306 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001307 struct brcmf_cfg80211_security *sec;
1308 s32 val = 0;
1309 s32 err = 0;
1310
1311 switch (sme->auth_type) {
1312 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1313 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001314 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001315 break;
1316 case NL80211_AUTHTYPE_SHARED_KEY:
1317 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001318 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001319 break;
1320 case NL80211_AUTHTYPE_AUTOMATIC:
1321 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001322 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001323 break;
1324 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001325 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001326 default:
1327 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001328 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001329 break;
1330 }
1331
Hante Meuleman89286dc2013-02-08 15:53:46 +01001332 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001333 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001334 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001335 return err;
1336 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001337 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001338 sec->auth_type = sme->auth_type;
1339 return err;
1340}
1341
1342static s32
1343brcmf_set_set_cipher(struct net_device *ndev,
1344 struct cfg80211_connect_params *sme)
1345{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001346 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001347 struct brcmf_cfg80211_security *sec;
1348 s32 pval = 0;
1349 s32 gval = 0;
1350 s32 err = 0;
1351
1352 if (sme->crypto.n_ciphers_pairwise) {
1353 switch (sme->crypto.ciphers_pairwise[0]) {
1354 case WLAN_CIPHER_SUITE_WEP40:
1355 case WLAN_CIPHER_SUITE_WEP104:
1356 pval = WEP_ENABLED;
1357 break;
1358 case WLAN_CIPHER_SUITE_TKIP:
1359 pval = TKIP_ENABLED;
1360 break;
1361 case WLAN_CIPHER_SUITE_CCMP:
1362 pval = AES_ENABLED;
1363 break;
1364 case WLAN_CIPHER_SUITE_AES_CMAC:
1365 pval = AES_ENABLED;
1366 break;
1367 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001368 brcmf_err("invalid cipher pairwise (%d)\n",
1369 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001370 return -EINVAL;
1371 }
1372 }
1373 if (sme->crypto.cipher_group) {
1374 switch (sme->crypto.cipher_group) {
1375 case WLAN_CIPHER_SUITE_WEP40:
1376 case WLAN_CIPHER_SUITE_WEP104:
1377 gval = WEP_ENABLED;
1378 break;
1379 case WLAN_CIPHER_SUITE_TKIP:
1380 gval = TKIP_ENABLED;
1381 break;
1382 case WLAN_CIPHER_SUITE_CCMP:
1383 gval = AES_ENABLED;
1384 break;
1385 case WLAN_CIPHER_SUITE_AES_CMAC:
1386 gval = AES_ENABLED;
1387 break;
1388 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001389 brcmf_err("invalid cipher group (%d)\n",
1390 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001391 return -EINVAL;
1392 }
1393 }
1394
Arend van Spriel16886732012-12-05 15:26:04 +01001395 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001396 /* In case of privacy, but no security and WPS then simulate */
1397 /* setting AES. WPS-2.0 allows no security */
1398 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1399 sme->privacy)
1400 pval = AES_ENABLED;
1401 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001402 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001403 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001404 return err;
1405 }
1406
Arend van Spriel06bb1232012-09-27 14:17:56 +02001407 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1409 sec->cipher_group = sme->crypto.cipher_group;
1410
1411 return err;
1412}
1413
1414static s32
1415brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1416{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001417 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001418 struct brcmf_cfg80211_security *sec;
1419 s32 val = 0;
1420 s32 err = 0;
1421
1422 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001423 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1424 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001425 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001426 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001427 return err;
1428 }
1429 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1430 switch (sme->crypto.akm_suites[0]) {
1431 case WLAN_AKM_SUITE_8021X:
1432 val = WPA_AUTH_UNSPECIFIED;
1433 break;
1434 case WLAN_AKM_SUITE_PSK:
1435 val = WPA_AUTH_PSK;
1436 break;
1437 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001438 brcmf_err("invalid cipher group (%d)\n",
1439 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 return -EINVAL;
1441 }
1442 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1443 switch (sme->crypto.akm_suites[0]) {
1444 case WLAN_AKM_SUITE_8021X:
1445 val = WPA2_AUTH_UNSPECIFIED;
1446 break;
1447 case WLAN_AKM_SUITE_PSK:
1448 val = WPA2_AUTH_PSK;
1449 break;
1450 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001451 brcmf_err("invalid cipher group (%d)\n",
1452 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453 return -EINVAL;
1454 }
1455 }
1456
Arend van Spriel16886732012-12-05 15:26:04 +01001457 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001458 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1459 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001460 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001461 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001462 return err;
1463 }
1464 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001465 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466 sec->wpa_auth = sme->crypto.akm_suites[0];
1467
1468 return err;
1469}
1470
1471static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001472brcmf_set_sharedkey(struct net_device *ndev,
1473 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001475 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001476 struct brcmf_cfg80211_security *sec;
1477 struct brcmf_wsec_key key;
1478 s32 val;
1479 s32 err = 0;
1480
Arend van Spriel16886732012-12-05 15:26:04 +01001481 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482
Roland Vossena718e2f2011-10-12 20:51:24 +02001483 if (sme->key_len == 0)
1484 return 0;
1485
Arend van Spriel06bb1232012-09-27 14:17:56 +02001486 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001487 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1488 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001489
1490 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1491 return 0;
1492
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001493 if (!(sec->cipher_pairwise &
1494 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1495 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001496
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001497 memset(&key, 0, sizeof(key));
1498 key.len = (u32) sme->key_len;
1499 key.index = (u32) sme->key_idx;
1500 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001501 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001502 return -EINVAL;
1503 }
1504 memcpy(key.data, sme->key, key.len);
1505 key.flags = BRCMF_PRIMARY_KEY;
1506 switch (sec->cipher_pairwise) {
1507 case WLAN_CIPHER_SUITE_WEP40:
1508 key.algo = CRYPTO_ALGO_WEP1;
1509 break;
1510 case WLAN_CIPHER_SUITE_WEP104:
1511 key.algo = CRYPTO_ALGO_WEP128;
1512 break;
1513 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001514 brcmf_err("Invalid algorithm (%d)\n",
1515 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001516 return -EINVAL;
1517 }
1518 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001519 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1520 key.len, key.index, key.algo);
1521 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001522 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001523 if (err)
1524 return err;
1525
1526 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001527 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001528 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001529 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001530 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001531 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001532 }
1533 return err;
1534}
1535
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001536static
1537enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1538 enum nl80211_auth_type type)
1539{
1540 u32 ci;
1541 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1542 /* shift to ignore chip revision */
1543 ci = brcmf_get_chip_info(ifp) >> 4;
1544 switch (ci) {
1545 case 43236:
1546 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1547 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1548 default:
1549 break;
1550 }
1551 }
1552 return type;
1553}
1554
Arend van Spriel5b435de2011-10-05 13:19:03 +02001555static s32
1556brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001557 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001558{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001559 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001560 struct brcmf_if *ifp = netdev_priv(ndev);
1561 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001562 struct ieee80211_channel *chan = sme->channel;
1563 struct brcmf_join_params join_params;
1564 size_t join_params_size;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001565 struct brcmf_tlv *rsn_ie;
1566 struct brcmf_vs_tlv *wpa_ie;
1567 void *ie;
1568 u32 ie_len;
1569 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001570 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001571
1572 s32 err = 0;
1573
Arend van Sprield96b8012012-12-05 15:26:02 +01001574 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001575 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001576 return -EIO;
1577
1578 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001579 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001580 return -EOPNOTSUPP;
1581 }
1582
Hante Meuleman89286dc2013-02-08 15:53:46 +01001583 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1584 /* A normal (non P2P) connection request setup. */
1585 ie = NULL;
1586 ie_len = 0;
1587 /* find the WPA_IE */
1588 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1589 if (wpa_ie) {
1590 ie = wpa_ie;
1591 ie_len = wpa_ie->len + TLV_HDR_LEN;
1592 } else {
1593 /* find the RSN_IE */
1594 rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
1595 WLAN_EID_RSN);
1596 if (rsn_ie) {
1597 ie = rsn_ie;
1598 ie_len = rsn_ie->len + TLV_HDR_LEN;
1599 }
1600 }
1601 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1602 }
1603
1604 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1605 sme->ie, sme->ie_len);
1606 if (err)
1607 brcmf_err("Set Assoc REQ IE Failed\n");
1608 else
1609 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1610
Arend van Sprielc1179032012-10-22 13:55:33 -07001611 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001612
1613 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001614 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001615 ieee80211_frequency_to_channel(chan->center_freq);
Franky Lin83cf17a2013-04-11 13:28:50 +02001616 chanspec = channel_to_chanspec(&cfg->d11inf, chan);
Hante Meuleman17012612013-02-06 18:40:44 +01001617 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1618 cfg->channel, chan->center_freq, chanspec);
1619 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001620 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001621 chanspec = 0;
1622 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001623
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001624 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625
1626 err = brcmf_set_wpa_version(ndev, sme);
1627 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001628 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001629 goto done;
1630 }
1631
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001632 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001633 err = brcmf_set_auth_type(ndev, sme);
1634 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001635 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001636 goto done;
1637 }
1638
1639 err = brcmf_set_set_cipher(ndev, sme);
1640 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001641 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001642 goto done;
1643 }
1644
1645 err = brcmf_set_key_mgmt(ndev, sme);
1646 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001647 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001648 goto done;
1649 }
1650
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001651 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001652 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001653 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001654 goto done;
1655 }
1656
Hante Meuleman89286dc2013-02-08 15:53:46 +01001657 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1658 (u32)sme->ssid_len);
1659 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1660 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1661 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1662 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1663 profile->ssid.SSID_len);
1664 }
1665
1666 /* Join with specific BSSID and cached SSID
1667 * If SSID is zero join based on BSSID only
1668 */
1669 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1670 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1671 if (cfg->channel)
1672 join_params_size += sizeof(u16);
1673 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1674 if (ext_join_params == NULL) {
1675 err = -ENOMEM;
1676 goto done;
1677 }
1678 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1679 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1680 profile->ssid.SSID_len);
1681 /*increase dwell time to receive probe response or detect Beacon
1682 * from target AP at a noisy air only during connect command
1683 */
1684 ext_join_params->scan_le.active_time =
1685 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1686 ext_join_params->scan_le.passive_time =
1687 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1688 /* Set up join scan parameters */
1689 ext_join_params->scan_le.scan_type = -1;
1690 /* to sync with presence period of VSDB GO.
1691 * Send probe request more frequently. Probe request will be stopped
1692 * when it gets probe response from target AP/GO.
1693 */
1694 ext_join_params->scan_le.nprobes =
1695 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1696 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1697 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1698
1699 if (sme->bssid)
1700 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1701 else
1702 memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
1703
1704 if (cfg->channel) {
1705 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1706
1707 ext_join_params->assoc_le.chanspec_list[0] =
1708 cpu_to_le16(chanspec);
1709 }
1710
1711 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1712 join_params_size);
1713 kfree(ext_join_params);
1714 if (!err)
1715 /* This is it. join command worked, we are done */
1716 goto done;
1717
1718 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001719 memset(&join_params, 0, sizeof(join_params));
1720 join_params_size = sizeof(join_params.ssid_le);
1721
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001722 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001723 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001724
Hante Meuleman89286dc2013-02-08 15:53:46 +01001725 if (sme->bssid)
1726 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1727 else
1728 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001729
Hante Meuleman17012612013-02-06 18:40:44 +01001730 if (cfg->channel) {
1731 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1732 join_params.params_le.chanspec_num = cpu_to_le32(1);
1733 join_params_size += sizeof(join_params.params_le);
1734 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001735 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001736 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001737 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001738 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001739
1740done:
1741 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001742 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001743 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001744 return err;
1745}
1746
1747static s32
1748brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1749 u16 reason_code)
1750{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001751 struct brcmf_if *ifp = netdev_priv(ndev);
1752 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001753 struct brcmf_scb_val_le scbval;
1754 s32 err = 0;
1755
Arend van Sprield96b8012012-12-05 15:26:02 +01001756 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001757 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001758 return -EIO;
1759
Arend van Sprielc1179032012-10-22 13:55:33 -07001760 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel43dffbc2014-01-06 12:40:46 +01001761 cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001762
Arend van Spriel06bb1232012-09-27 14:17:56 +02001763 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001764 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001765 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001766 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001767 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001768 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001769
Arend van Sprield96b8012012-12-05 15:26:02 +01001770 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001771 return err;
1772}
1773
1774static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001775brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001776 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001777{
1778
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001779 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001780 struct net_device *ndev = cfg_to_ndev(cfg);
1781 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001782 u16 txpwrmw;
1783 s32 err = 0;
1784 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001785 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001786
Arend van Sprield96b8012012-12-05 15:26:02 +01001787 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001788 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001789 return -EIO;
1790
1791 switch (type) {
1792 case NL80211_TX_POWER_AUTOMATIC:
1793 break;
1794 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001795 case NL80211_TX_POWER_FIXED:
1796 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001797 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001798 err = -EINVAL;
1799 goto done;
1800 }
1801 break;
1802 }
1803 /* Make sure radio is off or on as far as software is concerned */
1804 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001805 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001806 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001807 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001808
1809 if (dbm > 0xffff)
1810 txpwrmw = 0xffff;
1811 else
1812 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001813 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1814 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001815 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001816 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001817 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001818
1819done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001820 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001821 return err;
1822}
1823
Johannes Bergc8442112012-10-24 10:17:18 +02001824static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1825 struct wireless_dev *wdev,
1826 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001827{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001828 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001829 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001830 s32 txpwrdbm;
1831 u8 result;
1832 s32 err = 0;
1833
Arend van Sprield96b8012012-12-05 15:26:02 +01001834 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001835 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001836 return -EIO;
1837
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001838 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001839 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001840 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001841 goto done;
1842 }
1843
1844 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001845 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001846
1847done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001848 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001849 return err;
1850}
1851
1852static s32
1853brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1854 u8 key_idx, bool unicast, bool multicast)
1855{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001856 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001857 u32 index;
1858 u32 wsec;
1859 s32 err = 0;
1860
Arend van Sprield96b8012012-12-05 15:26:02 +01001861 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001862 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001863 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001864 return -EIO;
1865
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001866 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001867 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001868 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001869 goto done;
1870 }
1871
1872 if (wsec & WEP_ENABLED) {
1873 /* Just select a new current key */
1874 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001875 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001876 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001877 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001878 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001879 }
1880done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001881 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001882 return err;
1883}
1884
1885static s32
1886brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1887 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1888{
Hante Meuleman992f6062013-04-02 21:06:17 +02001889 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001890 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001891 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02001892 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02001893
1894 memset(&key, 0, sizeof(key));
1895 key.index = (u32) key_idx;
1896 /* Instead of bcast for ea address for default wep keys,
1897 driver needs it to be Null */
1898 if (!is_multicast_ether_addr(mac_addr))
1899 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1900 key.len = (u32) params->key_len;
1901 /* check for key index change */
1902 if (key.len == 0) {
1903 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001904 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001905 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001906 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001907 } else {
1908 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001909 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910 return -EINVAL;
1911 }
1912
Arend van Spriel16886732012-12-05 15:26:04 +01001913 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001914 memcpy(key.data, params->key, key.len);
1915
Hante Meuleman992f6062013-04-02 21:06:17 +02001916 if ((ifp->vif->mode != WL_MODE_AP) &&
1917 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1918 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001919 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1920 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1921 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1922 }
1923
1924 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1925 if (params->seq && params->seq_len == 6) {
1926 /* rx iv */
1927 u8 *ivptr;
1928 ivptr = (u8 *) params->seq;
1929 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1930 (ivptr[3] << 8) | ivptr[2];
1931 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1932 key.iv_initialized = true;
1933 }
1934
1935 switch (params->cipher) {
1936 case WLAN_CIPHER_SUITE_WEP40:
1937 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001938 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001939 break;
1940 case WLAN_CIPHER_SUITE_WEP104:
1941 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001942 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001943 break;
1944 case WLAN_CIPHER_SUITE_TKIP:
1945 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001946 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001947 break;
1948 case WLAN_CIPHER_SUITE_AES_CMAC:
1949 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001950 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001951 break;
1952 case WLAN_CIPHER_SUITE_CCMP:
1953 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001954 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001955 break;
1956 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001957 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001958 return -EINVAL;
1959 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001960 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001961 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001962 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001963 }
1964 return err;
1965}
1966
1967static s32
1968brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1969 u8 key_idx, bool pairwise, const u8 *mac_addr,
1970 struct key_params *params)
1971{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001972 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001973 struct brcmf_wsec_key key;
1974 s32 val;
1975 s32 wsec;
1976 s32 err = 0;
1977 u8 keybuf[8];
1978
Arend van Sprield96b8012012-12-05 15:26:02 +01001979 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001980 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001981 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001982 return -EIO;
1983
1984 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001985 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001986 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1987 }
1988 memset(&key, 0, sizeof(key));
1989
1990 key.len = (u32) params->key_len;
1991 key.index = (u32) key_idx;
1992
1993 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001994 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001995 err = -EINVAL;
1996 goto done;
1997 }
1998 memcpy(key.data, params->key, key.len);
1999
2000 key.flags = BRCMF_PRIMARY_KEY;
2001 switch (params->cipher) {
2002 case WLAN_CIPHER_SUITE_WEP40:
2003 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002004 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002005 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002006 break;
2007 case WLAN_CIPHER_SUITE_WEP104:
2008 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002009 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002010 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002011 break;
2012 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002013 if (ifp->vif->mode != WL_MODE_AP) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002014 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02002015 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2016 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2017 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2018 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002019 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002020 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002021 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002022 break;
2023 case WLAN_CIPHER_SUITE_AES_CMAC:
2024 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002025 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002026 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002027 break;
2028 case WLAN_CIPHER_SUITE_CCMP:
2029 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002030 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002031 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002032 break;
2033 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002034 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002035 err = -EINVAL;
2036 goto done;
2037 }
2038
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002039 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002040 if (err)
2041 goto done;
2042
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002043 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002044 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002045 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002046 goto done;
2047 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002049 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002051 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002052 goto done;
2053 }
2054
Arend van Spriel5b435de2011-10-05 13:19:03 +02002055done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002056 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057 return err;
2058}
2059
2060static s32
2061brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2062 u8 key_idx, bool pairwise, const u8 *mac_addr)
2063{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002064 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002065 struct brcmf_wsec_key key;
2066 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002067
Arend van Sprield96b8012012-12-05 15:26:02 +01002068 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002069 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002070 return -EIO;
2071
Hante Meuleman256c3742012-11-05 16:22:28 -08002072 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2073 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01002074 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08002075 return -EINVAL;
2076 }
2077
Arend van Spriel5b435de2011-10-05 13:19:03 +02002078 memset(&key, 0, sizeof(key));
2079
2080 key.index = (u32) key_idx;
2081 key.flags = BRCMF_PRIMARY_KEY;
2082 key.algo = CRYPTO_ALGO_OFF;
2083
Arend van Spriel16886732012-12-05 15:26:04 +01002084 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002085
2086 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002087 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002088
Arend van Sprield96b8012012-12-05 15:26:02 +01002089 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002090 return err;
2091}
2092
2093static s32
2094brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2095 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2096 void (*callback) (void *cookie, struct key_params * params))
2097{
2098 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002099 struct brcmf_if *ifp = netdev_priv(ndev);
2100 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002101 struct brcmf_cfg80211_security *sec;
2102 s32 wsec;
2103 s32 err = 0;
2104
Arend van Sprield96b8012012-12-05 15:26:02 +01002105 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002106 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002107 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002108 return -EIO;
2109
2110 memset(&params, 0, sizeof(params));
2111
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002112 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002113 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002114 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002115 /* Ignore this error, may happen during DISASSOC */
2116 err = -EAGAIN;
2117 goto done;
2118 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002119 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002120 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002121 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2122 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002123 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002124 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2125 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002126 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002127 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002128 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002130 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002131 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002133 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002134 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002135 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136 err = -EINVAL;
2137 goto done;
2138 }
2139 callback(cookie, &params);
2140
2141done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002142 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002143 return err;
2144}
2145
2146static s32
2147brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2148 struct net_device *ndev, u8 key_idx)
2149{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002150 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002151
2152 return -EOPNOTSUPP;
2153}
2154
2155static s32
2156brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002157 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002158{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002159 struct brcmf_if *ifp = netdev_priv(ndev);
2160 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002161 struct brcmf_scb_val_le scb_val;
2162 int rssi;
2163 s32 rate;
2164 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002165 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002166 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167
Arend van Sprield96b8012012-12-05 15:26:02 +01002168 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002169 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002170 return -EIO;
2171
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002172 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002173 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002174 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002175 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002176 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002177 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002178 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002179 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002180 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002181 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002182 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2183 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002184 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002185 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002186 }
Arend van Sprield96b8012012-12-05 15:26:02 +01002187 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2188 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002189 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002190 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002191 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2192 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02002193 err = -ENOENT;
2194 goto done;
2195 }
2196 /* Report the current tx rate */
Hante Meuleman89286dc2013-02-08 15:53:46 +01002197 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002198 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002199 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002200 goto done;
2201 } else {
2202 sinfo->filled |= STATION_INFO_TX_BITRATE;
2203 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002204 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002205 }
2206
Arend van Sprielc1179032012-10-22 13:55:33 -07002207 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2208 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002209 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002210 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2211 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002212 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002213 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002214 goto done;
2215 } else {
2216 rssi = le32_to_cpu(scb_val.val);
2217 sinfo->filled |= STATION_INFO_SIGNAL;
2218 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002219 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002220 }
2221 }
2222 } else
2223 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002224done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002225 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002226 return err;
2227}
2228
2229static s32
2230brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2231 bool enabled, s32 timeout)
2232{
2233 s32 pm;
2234 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002235 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002236 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002237
Arend van Sprield96b8012012-12-05 15:26:02 +01002238 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002239
2240 /*
2241 * Powersave enable/disable request is coming from the
2242 * cfg80211 even before the interface is up. In that
2243 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002244 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245 * FW later while initializing the dongle
2246 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002247 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002248 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002249
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002250 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251 goto done;
2252 }
2253
2254 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002255 /* Do not enable the power save after assoc if it is a p2p interface */
2256 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2257 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2258 pm = PM_OFF;
2259 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002260 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002261
Arend van Sprielc1179032012-10-22 13:55:33 -07002262 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002263 if (err) {
2264 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002265 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002266 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002267 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002268 }
2269done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002270 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002271 return err;
2272}
2273
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002274static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002275 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002276{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002277 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002278 struct ieee80211_channel *notify_channel;
2279 struct cfg80211_bss *bss;
2280 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002281 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002282 s32 err = 0;
2283 u16 channel;
2284 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002285 u16 notify_capability;
2286 u16 notify_interval;
2287 u8 *notify_ie;
2288 size_t notify_ielen;
2289 s32 notify_signal;
2290
2291 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002292 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002293 return 0;
2294 }
2295
Franky Lin83cf17a2013-04-11 13:28:50 +02002296 if (!bi->ctl_ch) {
2297 ch.chspec = le16_to_cpu(bi->chanspec);
2298 cfg->d11inf.decchspec(&ch);
2299 bi->ctl_ch = ch.chnum;
2300 }
2301 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002302
2303 if (channel <= CH_MAX_2G_CHANNEL)
2304 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2305 else
2306 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2307
2308 freq = ieee80211_channel_to_frequency(channel, band->band);
2309 notify_channel = ieee80211_get_channel(wiphy, freq);
2310
Arend van Spriel5b435de2011-10-05 13:19:03 +02002311 notify_capability = le16_to_cpu(bi->capability);
2312 notify_interval = le16_to_cpu(bi->beacon_period);
2313 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2314 notify_ielen = le32_to_cpu(bi->ie_length);
2315 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2316
Arend van Spriel16886732012-12-05 15:26:04 +01002317 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2318 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2319 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2320 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2321 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322
2323 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002324 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002325 notify_ielen, notify_signal, GFP_KERNEL);
2326
Franky Line78946e2011-11-10 20:30:34 +01002327 if (!bss)
2328 return -ENOMEM;
2329
Johannes Berg5b112d32013-02-01 01:49:58 +01002330 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002331
2332 return err;
2333}
2334
Roland Vossen6f09be02011-10-18 14:03:02 +02002335static struct brcmf_bss_info_le *
2336next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2337{
2338 if (bss == NULL)
2339 return list->bss_info_le;
2340 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2341 le32_to_cpu(bss->length));
2342}
2343
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002344static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002345{
2346 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002347 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002348 s32 err = 0;
2349 int i;
2350
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002351 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002352 if (bss_list->count != 0 &&
2353 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002354 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2355 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002356 return -EOPNOTSUPP;
2357 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002358 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002359 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002360 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002361 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002362 if (err)
2363 break;
2364 }
2365 return err;
2366}
2367
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002368static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002369 struct net_device *ndev, const u8 *bssid)
2370{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002371 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002372 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002373 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002374 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002375 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002376 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002377 u8 *buf = NULL;
2378 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002379 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002380 u16 notify_capability;
2381 u16 notify_interval;
2382 u8 *notify_ie;
2383 size_t notify_ielen;
2384 s32 notify_signal;
2385
Arend van Sprield96b8012012-12-05 15:26:02 +01002386 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002387
2388 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2389 if (buf == NULL) {
2390 err = -ENOMEM;
2391 goto CleanUp;
2392 }
2393
2394 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2395
Arend van Sprielac24be62012-10-22 10:36:23 -07002396 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2397 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002398 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002399 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002400 goto CleanUp;
2401 }
2402
Roland Vossend34bf642011-10-18 14:03:01 +02002403 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002404
Franky Lin83cf17a2013-04-11 13:28:50 +02002405 ch.chspec = le16_to_cpu(bi->chanspec);
2406 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002407
Franky Lin83cf17a2013-04-11 13:28:50 +02002408 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002409 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2410 else
2411 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2412
Franky Lin83cf17a2013-04-11 13:28:50 +02002413 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002414 notify_channel = ieee80211_get_channel(wiphy, freq);
2415
Arend van Spriel5b435de2011-10-05 13:19:03 +02002416 notify_capability = le16_to_cpu(bi->capability);
2417 notify_interval = le16_to_cpu(bi->beacon_period);
2418 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2419 notify_ielen = le32_to_cpu(bi->ie_length);
2420 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2421
Franky Lin83cf17a2013-04-11 13:28:50 +02002422 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002423 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2424 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2425 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002426
Franky Line78946e2011-11-10 20:30:34 +01002427 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002428 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002429 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2430
Franky Line78946e2011-11-10 20:30:34 +01002431 if (!bss) {
2432 err = -ENOMEM;
2433 goto CleanUp;
2434 }
2435
Johannes Berg5b112d32013-02-01 01:49:58 +01002436 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002437
Arend van Spriel5b435de2011-10-05 13:19:03 +02002438CleanUp:
2439
2440 kfree(buf);
2441
Arend van Sprield96b8012012-12-05 15:26:02 +01002442 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002443
2444 return err;
2445}
2446
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002447static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002448{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002449 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002450}
2451
Hante Meuleman89286dc2013-02-08 15:53:46 +01002452static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2453 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002454{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002455 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002456 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002457 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002458 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002459 u16 beacon_interval;
2460 u8 dtim_period;
2461 size_t ie_len;
2462 u8 *ie;
2463 s32 err = 0;
2464
Arend van Sprield96b8012012-12-05 15:26:02 +01002465 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002466 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002467 return err;
2468
Arend van Spriel06bb1232012-09-27 14:17:56 +02002469 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002470
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002471 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002472 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002473 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002474 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002475 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002476 goto update_bss_info_out;
2477 }
2478
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002479 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2480 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002481 if (err)
2482 goto update_bss_info_out;
2483
2484 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2485 ie_len = le32_to_cpu(bi->ie_length);
2486 beacon_interval = le16_to_cpu(bi->beacon_period);
2487
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002488 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002489 if (tim)
2490 dtim_period = tim->data[1];
2491 else {
2492 /*
2493 * active scan was done so we could not get dtim
2494 * information out of probe response.
2495 * so we speficially query dtim information to dongle.
2496 */
2497 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002498 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002499 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002500 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002501 goto update_bss_info_out;
2502 }
2503 dtim_period = (u8)var;
2504 }
2505
Arend van Spriel5b435de2011-10-05 13:19:03 +02002506update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002507 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002508 return err;
2509}
2510
Hante Meuleman18e2f612013-02-08 15:53:49 +01002511void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002512{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002513 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002514
Arend van Sprielc1179032012-10-22 13:55:33 -07002515 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002516 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002517 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002518 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002519 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002520 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2521 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002522}
2523
Hante Meulemane756af52012-09-11 21:18:52 +02002524static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2525{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002526 struct brcmf_cfg80211_info *cfg =
2527 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002528 escan_timeout_work);
2529
Arend van Spriela0f472a2013-04-05 10:57:49 +02002530 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002531}
2532
2533static void brcmf_escan_timeout(unsigned long data)
2534{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002535 struct brcmf_cfg80211_info *cfg =
2536 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002537
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002538 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002539 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002540 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002541 }
2542}
2543
2544static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002545brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2546 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002547 struct brcmf_bss_info_le *bss_info_le)
2548{
Franky Lin83cf17a2013-04-11 13:28:50 +02002549 struct brcmu_chan ch_bss, ch_bss_info_le;
2550
2551 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2552 cfg->d11inf.decchspec(&ch_bss);
2553 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2554 cfg->d11inf.decchspec(&ch_bss_info_le);
2555
Hante Meulemane756af52012-09-11 21:18:52 +02002556 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002557 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002558 bss_info_le->SSID_len == bss->SSID_len &&
2559 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002560 if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
2561 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002562 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2563 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2564
Hante Meulemane756af52012-09-11 21:18:52 +02002565 /* preserve max RSSI if the measurements are
2566 * both on-channel or both off-channel
2567 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002568 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002569 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002570 } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
2571 (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
Hante Meulemane756af52012-09-11 21:18:52 +02002572 /* preserve the on-channel rssi measurement
2573 * if the new measurement is off channel
2574 */
2575 bss->RSSI = bss_info_le->RSSI;
Arend van Spriel6f5838a2013-11-29 12:25:19 +01002576 bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
Hante Meulemane756af52012-09-11 21:18:52 +02002577 }
2578 return 1;
2579 }
2580 return 0;
2581}
2582
2583static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002584brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002585 const struct brcmf_event_msg *e, void *data)
2586{
Arend van Spriel19937322012-11-05 16:22:32 -08002587 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002588 s32 status;
2589 s32 err = 0;
2590 struct brcmf_escan_result_le *escan_result_le;
2591 struct brcmf_bss_info_le *bss_info_le;
2592 struct brcmf_bss_info_le *bss = NULL;
2593 u32 bi_length;
2594 struct brcmf_scan_results *list;
2595 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002596 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002597
Arend van Spriel5c36b992012-11-14 18:46:05 -08002598 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002599
Arend van Spriela0f472a2013-04-05 10:57:49 +02002600 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2601 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002602 return -EPERM;
2603 }
2604
2605 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002606 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002607 escan_result_le = (struct brcmf_escan_result_le *) data;
2608 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002609 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002610 goto exit;
2611 }
Hante Meulemane756af52012-09-11 21:18:52 +02002612 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002613 brcmf_err("Invalid bss_count %d: ignoring\n",
2614 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002615 goto exit;
2616 }
2617 bss_info_le = &escan_result_le->bss_info_le;
2618
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002619 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2620 goto exit;
2621
2622 if (!cfg->scan_request) {
2623 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2624 goto exit;
2625 }
2626
Hante Meulemane756af52012-09-11 21:18:52 +02002627 bi_length = le32_to_cpu(bss_info_le->length);
2628 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2629 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002630 brcmf_err("Invalid bss_info length %d: ignoring\n",
2631 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002632 goto exit;
2633 }
2634
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002635 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002636 BIT(NL80211_IFTYPE_ADHOC))) {
2637 if (le16_to_cpu(bss_info_le->capability) &
2638 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002639 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002640 goto exit;
2641 }
2642 }
2643
2644 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002645 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002646 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002647 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002648 goto exit;
2649 }
2650
2651 for (i = 0; i < list->count; i++) {
2652 bss = bss ? (struct brcmf_bss_info_le *)
2653 ((unsigned char *)bss +
2654 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02002655 if (brcmf_compare_update_same_bss(cfg, bss,
2656 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02002657 goto exit;
2658 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002659 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002660 bss_info_le, bi_length);
2661 list->version = le32_to_cpu(bss_info_le->version);
2662 list->buflen += bi_length;
2663 list->count++;
2664 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002665 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002666 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2667 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002668 if (cfg->scan_request) {
2669 cfg->bss_list = (struct brcmf_scan_results *)
2670 cfg->escan_info.escan_buf;
2671 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002672 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002673 brcmf_notify_escan_complete(cfg, ifp, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002674 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002675 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002676 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2677 status);
Hante Meulemane756af52012-09-11 21:18:52 +02002678 }
2679exit:
2680 return err;
2681}
2682
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002683static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002684{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002685 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2686 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002687 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2688 /* Init scan_timeout timer */
2689 init_timer(&cfg->escan_timeout);
2690 cfg->escan_timeout.data = (unsigned long) cfg;
2691 cfg->escan_timeout.function = brcmf_escan_timeout;
2692 INIT_WORK(&cfg->escan_timeout_work,
2693 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002694}
2695
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002696static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002697{
2698 if (ms < 1000 / HZ) {
2699 cond_resched();
2700 mdelay(ms);
2701 } else {
2702 msleep(ms);
2703 }
2704}
2705
2706static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2707{
Arend van Sprield96b8012012-12-05 15:26:02 +01002708 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002709
Arend van Spriel5b435de2011-10-05 13:19:03 +02002710 return 0;
2711}
2712
2713static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2714 struct cfg80211_wowlan *wow)
2715{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002716 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2717 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002718 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002719
Arend van Sprield96b8012012-12-05 15:26:02 +01002720 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002721
2722 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002723 * if the primary net_device is not READY there is nothing
2724 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002725 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002726 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2727 if (!check_vif_up(vif))
2728 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002729
Arend van Spriel7d641072012-10-22 13:55:39 -07002730 list_for_each_entry(vif, &cfg->vif_list, list) {
2731 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2732 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002733 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002734 * While going to suspend if associated with AP disassociate
2735 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002736 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002737 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002738
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002739 /* Make sure WPA_Supplicant receives all the event
2740 * generated due to DISASSOC call to the fw to keep
2741 * the state fw and WPA_Supplicant state consistent
2742 */
2743 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002744 }
2745
Arend van Spriel7d641072012-10-22 13:55:39 -07002746 /* end any scanning */
2747 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002748 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002749
2750 /* Turn off watchdog timer */
Arend van Sprielf96aa072013-04-05 10:57:48 +02002751 brcmf_set_mpc(netdev_priv(ndev), 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002752
Arend van Spriel7d641072012-10-22 13:55:39 -07002753exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002754 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002755 /* clear any scanning activity */
2756 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002757 return 0;
2758}
2759
2760static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002761brcmf_update_pmklist(struct net_device *ndev,
2762 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2763{
2764 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002765 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002766
Arend van Spriel40c8e952011-10-12 20:51:20 +02002767 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2768
Arend van Spriel16886732012-12-05 15:26:04 +01002769 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002770 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002771 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2772 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002773 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002774 brcmf_dbg(CONN, "%02x\n",
2775 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002776 }
2777
2778 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002779 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2780 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002781
2782 return err;
2783}
2784
2785static s32
2786brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2787 struct cfg80211_pmksa *pmksa)
2788{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002789 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002790 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002791 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002792 s32 err = 0;
2793 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002794 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002795
Arend van Sprield96b8012012-12-05 15:26:02 +01002796 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002797 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002798 return -EIO;
2799
Arend van Spriel40c8e952011-10-12 20:51:20 +02002800 pmkid_len = le32_to_cpu(pmkids->npmkid);
2801 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002802 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2803 break;
2804 if (i < WL_NUM_PMKIDS_MAX) {
2805 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2806 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002807 if (i == pmkid_len) {
2808 pmkid_len++;
2809 pmkids->npmkid = cpu_to_le32(pmkid_len);
2810 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002811 } else
2812 err = -EINVAL;
2813
Arend van Spriel16886732012-12-05 15:26:04 +01002814 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2815 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002816 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002817 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002818
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002819 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002820
Arend van Sprield96b8012012-12-05 15:26:02 +01002821 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002822 return err;
2823}
2824
2825static s32
2826brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2827 struct cfg80211_pmksa *pmksa)
2828{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002829 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002830 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002831 struct pmkid_list pmkid;
2832 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002833 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002834
Arend van Sprield96b8012012-12-05 15:26:02 +01002835 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002836 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002837 return -EIO;
2838
2839 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2840 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2841
Arend van Spriel16886732012-12-05 15:26:04 +01002842 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2843 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002844 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002845 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002846
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002847 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002848 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002849 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002850 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002851 ETH_ALEN))
2852 break;
2853
Arend van Spriel40c8e952011-10-12 20:51:20 +02002854 if ((pmkid_len > 0)
2855 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002856 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002857 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002858 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002859 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2860 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002861 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002862 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2863 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002864 WLAN_PMKID_LEN);
2865 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002866 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002867 } else
2868 err = -EINVAL;
2869
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002870 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002871
Arend van Sprield96b8012012-12-05 15:26:02 +01002872 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002873 return err;
2874
2875}
2876
2877static s32
2878brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2879{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002880 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002881 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002882 s32 err = 0;
2883
Arend van Sprield96b8012012-12-05 15:26:02 +01002884 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002885 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002886 return -EIO;
2887
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002888 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2889 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002890
Arend van Sprield96b8012012-12-05 15:26:02 +01002891 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002892 return err;
2893
2894}
2895
Arend van Spriele5806072012-09-19 22:21:08 +02002896/*
2897 * PFN result doesn't have all the info which are
2898 * required by the supplicant
2899 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2900 * via wl_inform_single_bss in the required format. Escan does require the
2901 * scan request in the form of cfg80211_scan_request. For timebeing, create
2902 * cfg80211_scan_request one out of the received PNO event.
2903 */
2904static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002905brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002906 const struct brcmf_event_msg *e, void *data)
2907{
Arend van Spriel19937322012-11-05 16:22:32 -08002908 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriele5806072012-09-19 22:21:08 +02002909 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2910 struct cfg80211_scan_request *request = NULL;
2911 struct cfg80211_ssid *ssid = NULL;
2912 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002913 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002914 int err = 0;
2915 int channel_req = 0;
2916 int band = 0;
2917 struct brcmf_pno_scanresults_le *pfn_result;
2918 u32 result_count;
2919 u32 status;
2920
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002921 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002922
Arend van Spriel5c36b992012-11-14 18:46:05 -08002923 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002924 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002925 return 0;
2926 }
2927
2928 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2929 result_count = le32_to_cpu(pfn_result->count);
2930 status = le32_to_cpu(pfn_result->status);
2931
2932 /*
2933 * PFN event is limited to fit 512 bytes so we may get
2934 * multiple NET_FOUND events. For now place a warning here.
2935 */
2936 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002937 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002938 if (result_count > 0) {
2939 int i;
2940
2941 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002942 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2943 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002944 if (!request || !ssid || !channel) {
2945 err = -ENOMEM;
2946 goto out_err;
2947 }
2948
2949 request->wiphy = wiphy;
2950 data += sizeof(struct brcmf_pno_scanresults_le);
2951 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2952
2953 for (i = 0; i < result_count; i++) {
2954 netinfo = &netinfo_start[i];
2955 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002956 brcmf_err("Invalid netinfo ptr. index: %d\n",
2957 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002958 err = -EINVAL;
2959 goto out_err;
2960 }
2961
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002962 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2963 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002964 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2965 ssid[i].ssid_len = netinfo->SSID_len;
2966 request->n_ssids++;
2967
2968 channel_req = netinfo->channel;
2969 if (channel_req <= CH_MAX_2G_CHANNEL)
2970 band = NL80211_BAND_2GHZ;
2971 else
2972 band = NL80211_BAND_5GHZ;
2973 channel[i].center_freq =
2974 ieee80211_channel_to_frequency(channel_req,
2975 band);
2976 channel[i].band = band;
2977 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2978 request->channels[i] = &channel[i];
2979 request->n_channels++;
2980 }
2981
2982 /* assign parsed ssid array */
2983 if (request->n_ssids)
2984 request->ssids = &ssid[0];
2985
Arend van Sprielc1179032012-10-22 13:55:33 -07002986 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002987 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002988 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002989 }
2990
Arend van Sprielc1179032012-10-22 13:55:33 -07002991 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002992 err = brcmf_do_escan(cfg, wiphy, ifp, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002993 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002994 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002995 goto out_err;
2996 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002997 cfg->sched_escan = true;
2998 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002999 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003000 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003001 goto out_err;
3002 }
3003
3004 kfree(ssid);
3005 kfree(channel);
3006 kfree(request);
3007 return 0;
3008
3009out_err:
3010 kfree(ssid);
3011 kfree(channel);
3012 kfree(request);
3013 cfg80211_sched_scan_stopped(wiphy);
3014 return err;
3015}
3016
Arend van Spriele5806072012-09-19 22:21:08 +02003017static int brcmf_dev_pno_clean(struct net_device *ndev)
3018{
Arend van Spriele5806072012-09-19 22:21:08 +02003019 int ret;
3020
3021 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003022 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003023 if (ret == 0) {
3024 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003025 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3026 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003027 }
3028 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003029 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003030
3031 return ret;
3032}
3033
3034static int brcmf_dev_pno_config(struct net_device *ndev)
3035{
3036 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003037
3038 memset(&pfn_param, 0, sizeof(pfn_param));
3039 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3040
3041 /* set extra pno params */
3042 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3043 pfn_param.repeat = BRCMF_PNO_REPEAT;
3044 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3045
3046 /* set up pno scan fr */
3047 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3048
Arend van Sprielac24be62012-10-22 10:36:23 -07003049 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3050 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003051}
3052
3053static int
3054brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3055 struct net_device *ndev,
3056 struct cfg80211_sched_scan_request *request)
3057{
Arend van Sprielc1179032012-10-22 13:55:33 -07003058 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003059 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003060 struct brcmf_pno_net_param_le pfn;
3061 int i;
3062 int ret = 0;
3063
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003064 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003065 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003066 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003067 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003068 return -EAGAIN;
3069 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02003070 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3071 brcmf_err("Scanning suppressed: status (%lu)\n",
3072 cfg->scan_status);
3073 return -EAGAIN;
3074 }
Arend van Spriele5806072012-09-19 22:21:08 +02003075
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003076 if (!request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003077 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003078 request->n_ssids);
Arend van Spriele5806072012-09-19 22:21:08 +02003079 return -EINVAL;
3080 }
3081
3082 if (request->n_ssids > 0) {
3083 for (i = 0; i < request->n_ssids; i++) {
3084 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003085 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3086 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003087
3088 /*
3089 * match_set ssids is a supert set of n_ssid list,
3090 * so we need not add these set seperately.
3091 */
3092 }
3093 }
3094
3095 if (request->n_match_sets > 0) {
3096 /* clean up everything */
3097 ret = brcmf_dev_pno_clean(ndev);
3098 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003099 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003100 return ret;
3101 }
3102
3103 /* configure pno */
3104 ret = brcmf_dev_pno_config(ndev);
3105 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003106 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003107 return -EINVAL;
3108 }
3109
3110 /* configure each match set */
3111 for (i = 0; i < request->n_match_sets; i++) {
3112 struct cfg80211_ssid *ssid;
3113 u32 ssid_len;
3114
3115 ssid = &request->match_sets[i].ssid;
3116 ssid_len = ssid->ssid_len;
3117
3118 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003119 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003120 continue;
3121 }
3122 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3123 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3124 pfn.wsec = cpu_to_le32(0);
3125 pfn.infra = cpu_to_le32(1);
3126 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3127 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3128 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003129 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003130 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003131 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3132 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003133 }
3134 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003135 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003136 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003137 return -EINVAL;
3138 }
3139 } else {
3140 return -EINVAL;
3141 }
3142
3143 return 0;
3144}
3145
3146static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3147 struct net_device *ndev)
3148{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003149 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003150
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003151 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003152 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003153 if (cfg->sched_escan)
Arend van Spriela0f472a2013-04-05 10:57:49 +02003154 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003155 return 0;
3156}
Arend van Spriele5806072012-09-19 22:21:08 +02003157
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003158#ifdef CONFIG_NL80211_TESTMODE
David Spinadelfc73f112013-07-31 18:04:15 +03003159static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
3160 struct wireless_dev *wdev,
3161 void *data, int len)
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003162{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003163 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003164 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003165 struct brcmf_dcmd *dcmd = data;
3166 struct sk_buff *reply;
3167 int ret;
3168
Arend van Sprield96b8012012-12-05 15:26:02 +01003169 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3170 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003171
3172 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003173 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3174 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003175 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003176 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3177 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003178 if (ret == 0) {
3179 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3180 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3181 ret = cfg80211_testmode_reply(reply);
3182 }
3183 return ret;
3184}
3185#endif
3186
Hante Meuleman1f170112013-02-06 18:40:38 +01003187static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003188{
3189 s32 err;
3190
3191 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003192 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003193 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003194 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003195 return err;
3196 }
3197 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003198 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003199 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003200 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003201 return err;
3202 }
3203 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003204 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003205 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003206 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003207 return err;
3208 }
3209
3210 return 0;
3211}
3212
3213static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3214{
3215 if (is_rsn_ie)
3216 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3217
3218 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3219}
3220
3221static s32
3222brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003223 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003224{
Arend van Sprielac24be62012-10-22 10:36:23 -07003225 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003226 u32 auth = 0; /* d11 open authentication */
3227 u16 count;
3228 s32 err = 0;
3229 s32 len = 0;
3230 u32 i;
3231 u32 wsec;
3232 u32 pval = 0;
3233 u32 gval = 0;
3234 u32 wpa_auth = 0;
3235 u32 offset;
3236 u8 *data;
3237 u16 rsn_cap;
3238 u32 wme_bss_disable;
3239
Arend van Sprield96b8012012-12-05 15:26:02 +01003240 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003241 if (wpa_ie == NULL)
3242 goto exit;
3243
3244 len = wpa_ie->len + TLV_HDR_LEN;
3245 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003246 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003247 if (!is_rsn_ie)
3248 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003249 else
3250 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003251
3252 /* check for multicast cipher suite */
3253 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3254 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003255 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003256 goto exit;
3257 }
3258
3259 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3260 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003261 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003262 goto exit;
3263 }
3264 offset += TLV_OUI_LEN;
3265
3266 /* pick up multicast cipher */
3267 switch (data[offset]) {
3268 case WPA_CIPHER_NONE:
3269 gval = 0;
3270 break;
3271 case WPA_CIPHER_WEP_40:
3272 case WPA_CIPHER_WEP_104:
3273 gval = WEP_ENABLED;
3274 break;
3275 case WPA_CIPHER_TKIP:
3276 gval = TKIP_ENABLED;
3277 break;
3278 case WPA_CIPHER_AES_CCM:
3279 gval = AES_ENABLED;
3280 break;
3281 default:
3282 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003283 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003284 goto exit;
3285 }
3286
3287 offset++;
3288 /* walk thru unicast cipher list and pick up what we recognize */
3289 count = data[offset] + (data[offset + 1] << 8);
3290 offset += WPA_IE_SUITE_COUNT_LEN;
3291 /* Check for unicast suite(s) */
3292 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3293 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003294 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003295 goto exit;
3296 }
3297 for (i = 0; i < count; i++) {
3298 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3299 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003300 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003301 goto exit;
3302 }
3303 offset += TLV_OUI_LEN;
3304 switch (data[offset]) {
3305 case WPA_CIPHER_NONE:
3306 break;
3307 case WPA_CIPHER_WEP_40:
3308 case WPA_CIPHER_WEP_104:
3309 pval |= WEP_ENABLED;
3310 break;
3311 case WPA_CIPHER_TKIP:
3312 pval |= TKIP_ENABLED;
3313 break;
3314 case WPA_CIPHER_AES_CCM:
3315 pval |= AES_ENABLED;
3316 break;
3317 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003318 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003319 }
3320 offset++;
3321 }
3322 /* walk thru auth management suite list and pick up what we recognize */
3323 count = data[offset] + (data[offset + 1] << 8);
3324 offset += WPA_IE_SUITE_COUNT_LEN;
3325 /* Check for auth key management suite(s) */
3326 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3327 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003328 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003329 goto exit;
3330 }
3331 for (i = 0; i < count; i++) {
3332 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3333 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003334 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003335 goto exit;
3336 }
3337 offset += TLV_OUI_LEN;
3338 switch (data[offset]) {
3339 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003340 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003341 wpa_auth |= WPA_AUTH_NONE;
3342 break;
3343 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003344 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003345 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3346 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3347 break;
3348 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003349 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003350 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3351 (wpa_auth |= WPA_AUTH_PSK);
3352 break;
3353 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003354 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003355 }
3356 offset++;
3357 }
3358
3359 if (is_rsn_ie) {
3360 wme_bss_disable = 1;
3361 if ((offset + RSN_CAP_LEN) <= len) {
3362 rsn_cap = data[offset] + (data[offset + 1] << 8);
3363 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3364 wme_bss_disable = 0;
3365 }
3366 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003367 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003368 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003369 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003370 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003371 goto exit;
3372 }
3373 }
3374 /* FOR WPS , set SES_OW_ENABLED */
3375 wsec = (pval | gval | SES_OW_ENABLED);
3376
3377 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003378 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003379 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003380 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003381 goto exit;
3382 }
3383 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003384 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003385 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003386 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003387 goto exit;
3388 }
3389 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003390 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003391 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003392 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003393 goto exit;
3394 }
3395
3396exit:
3397 return err;
3398}
3399
3400static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003401brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003402 struct parsed_vndr_ies *vndr_ies)
3403{
3404 s32 err = 0;
3405 struct brcmf_vs_tlv *vndrie;
3406 struct brcmf_tlv *ie;
3407 struct parsed_vndr_ie_info *parsed_info;
3408 s32 remaining_len;
3409
3410 remaining_len = (s32)vndr_ie_len;
3411 memset(vndr_ies, 0, sizeof(*vndr_ies));
3412
3413 ie = (struct brcmf_tlv *)vndr_ie_buf;
3414 while (ie) {
3415 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3416 goto next;
3417 vndrie = (struct brcmf_vs_tlv *)ie;
3418 /* len should be bigger than OUI length + one */
3419 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003420 brcmf_err("invalid vndr ie. length is too small %d\n",
3421 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003422 goto next;
3423 }
3424 /* if wpa or wme ie, do not add ie */
3425 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3426 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3427 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003428 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003429 goto next;
3430 }
3431
3432 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3433
3434 /* save vndr ie information */
3435 parsed_info->ie_ptr = (char *)vndrie;
3436 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3437 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3438
3439 vndr_ies->count++;
3440
Arend van Sprield96b8012012-12-05 15:26:02 +01003441 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3442 parsed_info->vndrie.oui[0],
3443 parsed_info->vndrie.oui[1],
3444 parsed_info->vndrie.oui[2],
3445 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003446
Arend van Spriel9f440b72013-02-08 15:53:36 +01003447 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003448 break;
3449next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003450 remaining_len -= (ie->len + TLV_HDR_LEN);
3451 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003452 ie = NULL;
3453 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003454 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3455 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003456 }
3457 return err;
3458}
3459
3460static u32
3461brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3462{
3463
3464 __le32 iecount_le;
3465 __le32 pktflag_le;
3466
3467 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3468 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3469
3470 iecount_le = cpu_to_le32(1);
3471 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3472
3473 pktflag_le = cpu_to_le32(pktflag);
3474 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3475
3476 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3477
3478 return ie_len + VNDR_IE_HDR_SIZE;
3479}
3480
Arend van Spriel1332e262012-11-05 16:22:18 -08003481s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3482 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003483{
Arend van Spriel1332e262012-11-05 16:22:18 -08003484 struct brcmf_if *ifp;
3485 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003486 s32 err = 0;
3487 u8 *iovar_ie_buf;
3488 u8 *curr_ie_buf;
3489 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003490 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003491 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003492 u32 del_add_ie_buf_len = 0;
3493 u32 total_ie_buf_len = 0;
3494 u32 parsed_ie_buf_len = 0;
3495 struct parsed_vndr_ies old_vndr_ies;
3496 struct parsed_vndr_ies new_vndr_ies;
3497 struct parsed_vndr_ie_info *vndrie_info;
3498 s32 i;
3499 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003500 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003501
Arend van Spriel1332e262012-11-05 16:22:18 -08003502 if (!vif)
3503 return -ENODEV;
3504 ifp = vif->ifp;
3505 saved_ie = &vif->saved_ie;
3506
Arend van Sprield96b8012012-12-05 15:26:02 +01003507 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003508 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3509 if (!iovar_ie_buf)
3510 return -ENOMEM;
3511 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003512 switch (pktflag) {
3513 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3514 mgmt_ie_buf = saved_ie->probe_req_ie;
3515 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3516 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3517 break;
3518 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3519 mgmt_ie_buf = saved_ie->probe_res_ie;
3520 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3521 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3522 break;
3523 case BRCMF_VNDR_IE_BEACON_FLAG:
3524 mgmt_ie_buf = saved_ie->beacon_ie;
3525 mgmt_ie_len = &saved_ie->beacon_ie_len;
3526 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3527 break;
3528 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3529 mgmt_ie_buf = saved_ie->assoc_req_ie;
3530 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3531 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3532 break;
3533 default:
3534 err = -EPERM;
3535 brcmf_err("not suitable type\n");
3536 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003537 }
3538
3539 if (vndr_ie_len > mgmt_ie_buf_len) {
3540 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003541 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003542 goto exit;
3543 }
3544
3545 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3546 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3547 ptr = curr_ie_buf;
3548 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3549 for (i = 0; i < new_vndr_ies.count; i++) {
3550 vndrie_info = &new_vndr_ies.ie_info[i];
3551 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3552 vndrie_info->ie_len);
3553 parsed_ie_buf_len += vndrie_info->ie_len;
3554 }
3555 }
3556
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003557 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003558 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3559 (memcmp(mgmt_ie_buf, curr_ie_buf,
3560 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003561 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003562 goto exit;
3563 }
3564
3565 /* parse old vndr_ie */
3566 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3567
3568 /* make a command to delete old ie */
3569 for (i = 0; i < old_vndr_ies.count; i++) {
3570 vndrie_info = &old_vndr_ies.ie_info[i];
3571
Arend van Sprield96b8012012-12-05 15:26:02 +01003572 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3573 vndrie_info->vndrie.id,
3574 vndrie_info->vndrie.len,
3575 vndrie_info->vndrie.oui[0],
3576 vndrie_info->vndrie.oui[1],
3577 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003578
3579 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3580 vndrie_info->ie_ptr,
3581 vndrie_info->ie_len,
3582 "del");
3583 curr_ie_buf += del_add_ie_buf_len;
3584 total_ie_buf_len += del_add_ie_buf_len;
3585 }
3586 }
3587
3588 *mgmt_ie_len = 0;
3589 /* Add if there is any extra IE */
3590 if (mgmt_ie_buf && parsed_ie_buf_len) {
3591 ptr = mgmt_ie_buf;
3592
3593 remained_buf_len = mgmt_ie_buf_len;
3594
3595 /* make a command to add new ie */
3596 for (i = 0; i < new_vndr_ies.count; i++) {
3597 vndrie_info = &new_vndr_ies.ie_info[i];
3598
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003599 /* verify remained buf size before copy data */
3600 if (remained_buf_len < (vndrie_info->vndrie.len +
3601 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003602 brcmf_err("no space in mgmt_ie_buf: len left %d",
3603 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003604 break;
3605 }
3606 remained_buf_len -= (vndrie_info->ie_len +
3607 VNDR_IE_VSIE_OFFSET);
3608
Arend van Sprield96b8012012-12-05 15:26:02 +01003609 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3610 vndrie_info->vndrie.id,
3611 vndrie_info->vndrie.len,
3612 vndrie_info->vndrie.oui[0],
3613 vndrie_info->vndrie.oui[1],
3614 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003615
3616 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3617 vndrie_info->ie_ptr,
3618 vndrie_info->ie_len,
3619 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003620
3621 /* save the parsed IE in wl struct */
3622 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3623 vndrie_info->ie_len);
3624 *mgmt_ie_len += vndrie_info->ie_len;
3625
3626 curr_ie_buf += del_add_ie_buf_len;
3627 total_ie_buf_len += del_add_ie_buf_len;
3628 }
3629 }
3630 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003631 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003632 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003633 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003634 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003635 }
3636
3637exit:
3638 kfree(iovar_ie_buf);
3639 return err;
3640}
3641
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003642s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3643{
3644 s32 pktflags[] = {
3645 BRCMF_VNDR_IE_PRBREQ_FLAG,
3646 BRCMF_VNDR_IE_PRBRSP_FLAG,
3647 BRCMF_VNDR_IE_BEACON_FLAG
3648 };
3649 int i;
3650
3651 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3652 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3653
3654 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3655 return 0;
3656}
3657
Hante Meuleman1a873342012-09-27 14:17:54 +02003658static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01003659brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3660 struct cfg80211_beacon_data *beacon)
3661{
3662 s32 err;
3663
3664 /* Set Beacon IEs to FW */
3665 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3666 beacon->tail, beacon->tail_len);
3667 if (err) {
3668 brcmf_err("Set Beacon IE Failed\n");
3669 return err;
3670 }
3671 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3672
3673 /* Set Probe Response IEs to FW */
3674 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3675 beacon->proberesp_ies,
3676 beacon->proberesp_ies_len);
3677 if (err)
3678 brcmf_err("Set Probe Resp IE Failed\n");
3679 else
3680 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3681
3682 return err;
3683}
3684
3685static s32
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003686brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
3687 struct brcmf_if *ifp,
3688 struct ieee80211_channel *channel)
3689{
3690 u16 chanspec;
3691 s32 err;
3692
3693 brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
3694 channel->center_freq);
3695
3696 chanspec = channel_to_chanspec(&cfg->d11inf, channel);
3697 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3698
3699 return err;
3700}
3701
3702static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02003703brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3704 struct cfg80211_ap_settings *settings)
3705{
3706 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003707 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07003708 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003709 struct brcmf_tlv *ssid_ie;
3710 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003711 s32 err = -EPERM;
3712 struct brcmf_tlv *rsn_ie;
3713 struct brcmf_vs_tlv *wpa_ie;
3714 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01003715 enum nl80211_iftype dev_role;
3716 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003717
Arend van Sprield96b8012012-12-05 15:26:02 +01003718 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3719 cfg80211_get_chandef_type(&settings->chandef),
3720 settings->beacon_interval,
3721 settings->dtim_period);
3722 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3723 settings->ssid, settings->ssid_len, settings->auth_type,
3724 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003725
Hante Meuleman426d0a52013-02-08 15:53:53 +01003726 dev_role = ifp->vif->wdev.iftype;
Hante Meuleman1a873342012-09-27 14:17:54 +02003727
3728 memset(&ssid_le, 0, sizeof(ssid_le));
3729 if (settings->ssid == NULL || settings->ssid_len == 0) {
3730 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3731 ssid_ie = brcmf_parse_tlvs(
3732 (u8 *)&settings->beacon.head[ie_offset],
3733 settings->beacon.head_len - ie_offset,
3734 WLAN_EID_SSID);
3735 if (!ssid_ie)
3736 return -EINVAL;
3737
3738 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3739 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003740 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003741 } else {
3742 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3743 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3744 }
3745
Arend van Sprielf96aa072013-04-05 10:57:48 +02003746 brcmf_set_mpc(ifp, 0);
Hante Meulemanb3657452013-05-27 21:09:53 +02003747 brcmf_configure_arp_offload(ifp, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003748
3749 /* find the RSN_IE */
3750 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3751 settings->beacon.tail_len, WLAN_EID_RSN);
3752
3753 /* find the WPA_IE */
3754 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3755 settings->beacon.tail_len);
3756
Hante Meuleman1a873342012-09-27 14:17:54 +02003757 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003758 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003759 if (wpa_ie != NULL) {
3760 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003761 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003762 if (err < 0)
3763 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003764 } else {
3765 /* RSN IE */
3766 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003767 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003768 if (err < 0)
3769 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003770 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003771 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003772 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003773 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003774 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003775
Hante Meulemana0f07952013-02-08 15:53:47 +01003776 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02003777
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003778 err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
3779 if (err < 0) {
3780 brcmf_err("Set Channel failed, %d\n", err);
3781 goto exit;
3782 }
3783
Hante Meuleman1a873342012-09-27 14:17:54 +02003784 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003785 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003786 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003787 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003788 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003789 goto exit;
3790 }
3791 }
3792 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003793 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003794 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003795 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003796 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003797 goto exit;
3798 }
3799 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003800
3801 if (dev_role == NL80211_IFTYPE_AP) {
3802 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3803 if (err < 0) {
3804 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3805 goto exit;
3806 }
Hante Meuleman2880b862013-02-08 12:06:31 +01003807 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003808 }
3809
Hante Meulemana0f07952013-02-08 15:53:47 +01003810 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003811 if (err < 0) {
Hante Meulemana0f07952013-02-08 15:53:47 +01003812 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003813 goto exit;
3814 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003815 if (dev_role == NL80211_IFTYPE_AP) {
3816 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3817 if (err < 0) {
3818 brcmf_err("setting AP mode failed %d\n", err);
3819 goto exit;
3820 }
3821 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3822 if (err < 0) {
3823 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3824 goto exit;
3825 }
3826
3827 memset(&join_params, 0, sizeof(join_params));
3828 /* join parameters starts with ssid */
3829 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3830 /* create softap */
3831 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3832 &join_params, sizeof(join_params));
3833 if (err < 0) {
3834 brcmf_err("SET SSID error (%d)\n", err);
3835 goto exit;
3836 }
3837 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3838 } else {
3839 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3840 sizeof(ssid_le));
3841 if (err < 0) {
3842 brcmf_err("setting ssid failed %d\n", err);
3843 goto exit;
3844 }
3845 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3846 bss_enable.enable = cpu_to_le32(1);
3847 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3848 sizeof(bss_enable));
3849 if (err < 0) {
3850 brcmf_err("bss_enable config failed %d\n", err);
3851 goto exit;
3852 }
3853
3854 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3855 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003856 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3857 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003858
3859exit:
Hante Meulemanb3657452013-05-27 21:09:53 +02003860 if (err) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02003861 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003862 brcmf_configure_arp_offload(ifp, true);
3863 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003864 return err;
3865}
3866
3867static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3868{
Arend van Sprielc1179032012-10-22 13:55:33 -07003869 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003870 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01003871 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02003872 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003873
Arend van Sprield96b8012012-12-05 15:26:02 +01003874 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003875
Hante Meuleman426d0a52013-02-08 15:53:53 +01003876 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003877 /* Due to most likely deauths outstanding we sleep */
3878 /* first to make sure they get processed by fw. */
3879 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003880
3881 memset(&join_params, 0, sizeof(join_params));
3882 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3883 &join_params, sizeof(join_params));
3884 if (err < 0)
3885 brcmf_err("SET SSID error (%d)\n", err);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003886 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003887 if (err < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003888 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003889 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3890 if (err < 0)
3891 brcmf_err("setting AP mode failed %d\n", err);
3892 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3893 if (err < 0)
3894 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003895 } else {
3896 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3897 bss_enable.enable = cpu_to_le32(0);
3898 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3899 sizeof(bss_enable));
3900 if (err < 0)
3901 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003902 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02003903 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003904 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003905 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3906 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3907
Hante Meuleman1a873342012-09-27 14:17:54 +02003908 return err;
3909}
3910
Hante Meulemana0f07952013-02-08 15:53:47 +01003911static s32
3912brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3913 struct cfg80211_beacon_data *info)
3914{
Hante Meulemana0f07952013-02-08 15:53:47 +01003915 struct brcmf_if *ifp = netdev_priv(ndev);
3916 s32 err;
3917
3918 brcmf_dbg(TRACE, "Enter\n");
3919
Hante Meulemana0f07952013-02-08 15:53:47 +01003920 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3921
3922 return err;
3923}
3924
Hante Meuleman1a873342012-09-27 14:17:54 +02003925static int
3926brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3927 u8 *mac)
3928{
Hante Meulemana0f07952013-02-08 15:53:47 +01003929 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003930 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003931 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003932 s32 err;
3933
3934 if (!mac)
3935 return -EFAULT;
3936
Arend van Sprield96b8012012-12-05 15:26:02 +01003937 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003938
Hante Meulemana0f07952013-02-08 15:53:47 +01003939 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3940 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07003941 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003942 return -EIO;
3943
3944 memcpy(&scbval.ea, mac, ETH_ALEN);
3945 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003946 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003947 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003948 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003949 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01003950
Arend van Sprield96b8012012-12-05 15:26:02 +01003951 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003952 return err;
3953}
3954
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003955
3956static void
3957brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3958 struct wireless_dev *wdev,
3959 u16 frame_type, bool reg)
3960{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02003961 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003962 u16 mgmt_type;
3963
3964 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3965
3966 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02003967 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003968 if (reg)
3969 vif->mgmt_rx_reg |= BIT(mgmt_type);
3970 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01003971 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003972}
3973
3974
3975static int
3976brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003977 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003978{
3979 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003980 struct ieee80211_channel *chan = params->chan;
3981 const u8 *buf = params->buf;
3982 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003983 const struct ieee80211_mgmt *mgmt;
3984 struct brcmf_cfg80211_vif *vif;
3985 s32 err = 0;
3986 s32 ie_offset;
3987 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01003988 struct brcmf_fil_action_frame_le *action_frame;
3989 struct brcmf_fil_af_params_le *af_params;
3990 bool ack;
3991 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02003992 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003993
3994 brcmf_dbg(TRACE, "Enter\n");
3995
3996 *cookie = 0;
3997
3998 mgmt = (const struct ieee80211_mgmt *)buf;
3999
Hante Meulemana0f07952013-02-08 15:53:47 +01004000 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4001 brcmf_err("Driver only allows MGMT packet type\n");
4002 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004003 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004004
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004005 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4006
Hante Meulemana0f07952013-02-08 15:53:47 +01004007 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4008 /* Right now the only reason to get a probe response */
4009 /* is for p2p listen response or for p2p GO from */
4010 /* wpa_supplicant. Unfortunately the probe is send */
4011 /* on primary ndev, while dongle wants it on the p2p */
4012 /* vif. Since this is only reason for a probe */
4013 /* response to be sent, the vif is taken from cfg. */
4014 /* If ever desired to send proberesp for non p2p */
4015 /* response then data should be checked for */
4016 /* "DIRECT-". Note in future supplicant will take */
4017 /* dedicated p2p wdev to do this and then this 'hack'*/
4018 /* is not needed anymore. */
4019 ie_offset = DOT11_MGMT_HDR_LEN +
4020 DOT11_BCN_PRB_FIXED_LEN;
4021 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004022 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4023 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4024 err = brcmf_vif_set_mgmt_ie(vif,
4025 BRCMF_VNDR_IE_PRBRSP_FLAG,
4026 &buf[ie_offset],
4027 ie_len);
4028 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4029 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004030 } else if (ieee80211_is_action(mgmt->frame_control)) {
4031 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4032 if (af_params == NULL) {
4033 brcmf_err("unable to allocate frame\n");
4034 err = -ENOMEM;
4035 goto exit;
4036 }
4037 action_frame = &af_params->action_frame;
4038 /* Add the packet Id */
4039 action_frame->packet_id = cpu_to_le32(*cookie);
4040 /* Add BSSID */
4041 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4042 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4043 /* Add the length exepted for 802.11 header */
4044 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004045 /* Add the channel. Use the one specified as parameter if any or
4046 * the current one (got from the firmware) otherwise
4047 */
4048 if (chan)
4049 freq = chan->center_freq;
4050 else
4051 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4052 &freq);
4053 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004054 af_params->channel = cpu_to_le32(chan_nr);
4055
4056 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4057 le16_to_cpu(action_frame->len));
4058
4059 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004060 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004061
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004062 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004063 af_params);
4064
4065 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4066 GFP_KERNEL);
4067 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004068 } else {
4069 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4070 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4071 }
4072
Hante Meuleman18e2f612013-02-08 15:53:49 +01004073exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004074 return err;
4075}
4076
4077
4078static int
4079brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4080 struct wireless_dev *wdev,
4081 u64 cookie)
4082{
4083 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4084 struct brcmf_cfg80211_vif *vif;
4085 int err = 0;
4086
4087 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4088
4089 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4090 if (vif == NULL) {
4091 brcmf_err("No p2p device available for probe response\n");
4092 err = -ENODEV;
4093 goto exit;
4094 }
4095 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4096exit:
4097 return err;
4098}
4099
Piotr Haber61730d42013-04-23 12:53:12 +02004100static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4101 struct wireless_dev *wdev,
4102 enum nl80211_crit_proto_id proto,
4103 u16 duration)
4104{
4105 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4106 struct brcmf_cfg80211_vif *vif;
4107
4108 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4109
4110 /* only DHCP support for now */
4111 if (proto != NL80211_CRIT_PROTO_DHCP)
4112 return -EINVAL;
4113
4114 /* suppress and abort scanning */
4115 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4116 brcmf_abort_scanning(cfg);
4117
4118 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4119}
4120
4121static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4122 struct wireless_dev *wdev)
4123{
4124 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4125 struct brcmf_cfg80211_vif *vif;
4126
4127 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4128
4129 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4130 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4131}
4132
Arend van Spriel89c2f382013-08-10 12:27:25 +02004133static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4134{
4135 int ret;
4136
4137 switch (oper) {
4138 case NL80211_TDLS_DISCOVERY_REQ:
4139 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4140 break;
4141 case NL80211_TDLS_SETUP:
4142 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4143 break;
4144 case NL80211_TDLS_TEARDOWN:
4145 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4146 break;
4147 default:
4148 brcmf_err("unsupported operation: %d\n", oper);
4149 ret = -EOPNOTSUPP;
4150 }
4151 return ret;
4152}
4153
4154static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
4155 struct net_device *ndev, u8 *peer,
4156 enum nl80211_tdls_operation oper)
4157{
4158 struct brcmf_if *ifp;
4159 struct brcmf_tdls_iovar_le info;
4160 int ret = 0;
4161
4162 ret = brcmf_convert_nl80211_tdls_oper(oper);
4163 if (ret < 0)
4164 return ret;
4165
4166 ifp = netdev_priv(ndev);
4167 memset(&info, 0, sizeof(info));
4168 info.mode = (u8)ret;
4169 if (peer)
4170 memcpy(info.ea, peer, ETH_ALEN);
4171
4172 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4173 &info, sizeof(info));
4174 if (ret < 0)
4175 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4176
4177 return ret;
4178}
4179
Arend van Spriel5b435de2011-10-05 13:19:03 +02004180static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004181 .add_virtual_intf = brcmf_cfg80211_add_iface,
4182 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004183 .change_virtual_intf = brcmf_cfg80211_change_iface,
4184 .scan = brcmf_cfg80211_scan,
4185 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4186 .join_ibss = brcmf_cfg80211_join_ibss,
4187 .leave_ibss = brcmf_cfg80211_leave_ibss,
4188 .get_station = brcmf_cfg80211_get_station,
4189 .set_tx_power = brcmf_cfg80211_set_tx_power,
4190 .get_tx_power = brcmf_cfg80211_get_tx_power,
4191 .add_key = brcmf_cfg80211_add_key,
4192 .del_key = brcmf_cfg80211_del_key,
4193 .get_key = brcmf_cfg80211_get_key,
4194 .set_default_key = brcmf_cfg80211_config_default_key,
4195 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4196 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004197 .connect = brcmf_cfg80211_connect,
4198 .disconnect = brcmf_cfg80211_disconnect,
4199 .suspend = brcmf_cfg80211_suspend,
4200 .resume = brcmf_cfg80211_resume,
4201 .set_pmksa = brcmf_cfg80211_set_pmksa,
4202 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004203 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004204 .start_ap = brcmf_cfg80211_start_ap,
4205 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004206 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004207 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004208 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4209 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004210 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4211 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4212 .remain_on_channel = brcmf_p2p_remain_on_channel,
4213 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004214 .start_p2p_device = brcmf_p2p_start_device,
4215 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004216 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4217 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004218 .tdls_oper = brcmf_cfg80211_tdls_oper,
Johannes Berge3335472013-08-06 11:13:19 +02004219 CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004220};
4221
Arend van Spriel9f440b72013-02-08 15:53:36 +01004222static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004223{
Arend van Spriel9f440b72013-02-08 15:53:36 +01004224 switch (type) {
4225 case NL80211_IFTYPE_AP_VLAN:
4226 case NL80211_IFTYPE_WDS:
4227 case NL80211_IFTYPE_MONITOR:
4228 case NL80211_IFTYPE_MESH_POINT:
4229 return -ENOTSUPP;
4230 case NL80211_IFTYPE_ADHOC:
4231 return WL_MODE_IBSS;
4232 case NL80211_IFTYPE_STATION:
4233 case NL80211_IFTYPE_P2P_CLIENT:
4234 return WL_MODE_BSS;
4235 case NL80211_IFTYPE_AP:
4236 case NL80211_IFTYPE_P2P_GO:
4237 return WL_MODE_AP;
4238 case NL80211_IFTYPE_P2P_DEVICE:
4239 return WL_MODE_P2P;
4240 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004241 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01004242 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004243 }
4244
Arend van Spriel9f440b72013-02-08 15:53:36 +01004245 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004246}
4247
Arend van Spriele5806072012-09-19 22:21:08 +02004248static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4249{
Arend van Spriele5806072012-09-19 22:21:08 +02004250 /* scheduled scan settings */
4251 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4252 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4253 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4254 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02004255}
4256
Arend van Spriel9f440b72013-02-08 15:53:36 +01004257static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4258 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004259 .max = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004260 .types = BIT(NL80211_IFTYPE_STATION) |
4261 BIT(NL80211_IFTYPE_ADHOC) |
4262 BIT(NL80211_IFTYPE_AP)
4263 },
4264 {
4265 .max = 1,
4266 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4267 BIT(NL80211_IFTYPE_P2P_GO)
4268 },
Arend van Spriel9af221b2013-05-14 20:52:36 +02004269 {
4270 .max = 1,
4271 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4272 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004273};
4274static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4275 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004276 .max_interfaces = BRCMF_IFACE_MAX_CNT,
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004277 .num_different_channels = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004278 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4279 .limits = brcmf_iface_limits
4280 }
4281};
4282
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004283static const struct ieee80211_txrx_stypes
4284brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4285 [NL80211_IFTYPE_STATION] = {
4286 .tx = 0xffff,
4287 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4288 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4289 },
4290 [NL80211_IFTYPE_P2P_CLIENT] = {
4291 .tx = 0xffff,
4292 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4293 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4294 },
4295 [NL80211_IFTYPE_P2P_GO] = {
4296 .tx = 0xffff,
4297 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4298 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4299 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4300 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4301 BIT(IEEE80211_STYPE_AUTH >> 4) |
4302 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4303 BIT(IEEE80211_STYPE_ACTION >> 4)
Arend van Sprielbffc61c2013-04-05 10:57:52 +02004304 },
4305 [NL80211_IFTYPE_P2P_DEVICE] = {
4306 .tx = 0xffff,
4307 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4308 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004309 }
4310};
4311
Arend van Spriel3eacf862012-10-22 13:55:30 -07004312static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004313{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004314 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004315 s32 err = 0;
4316
Arend van Spriel3eacf862012-10-22 13:55:30 -07004317 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4318 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004319 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004320 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004321 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004322 set_wiphy_dev(wiphy, phydev);
4323 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004324 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004325 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4326 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4327 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01004328 BIT(NL80211_IFTYPE_AP) |
4329 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Arend van Spriel9af221b2013-05-14 20:52:36 +02004330 BIT(NL80211_IFTYPE_P2P_GO) |
4331 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel9f440b72013-02-08 15:53:36 +01004332 wiphy->iface_combinations = brcmf_iface_combos;
4333 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004334 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004335 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4336 wiphy->cipher_suites = __wl_cipher_suites;
4337 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004338 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004339 WIPHY_FLAG_OFFCHAN_TX |
Arend van Spriel89c2f382013-08-10 12:27:25 +02004340 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
4341 WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004342 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4343 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004344 brcmf_wiphy_pno_params(wiphy);
Hante Meulemand48200b2013-04-03 12:40:29 +02004345 brcmf_dbg(INFO, "Registering custom regulatory\n");
Luis R. Rodrigueza2f73b62013-11-11 22:15:29 +01004346 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
Hante Meulemand48200b2013-04-03 12:40:29 +02004347 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004348 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004349 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004350 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004351 wiphy_free(wiphy);
4352 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004353 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004354 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004355}
4356
Arend van Spriel3eacf862012-10-22 13:55:30 -07004357struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004358 enum nl80211_iftype type,
4359 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004360{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004361 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004362
Arend van Spriel3eacf862012-10-22 13:55:30 -07004363 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4364 return ERR_PTR(-ENOSPC);
4365
Arend van Spriel33a6b152013-02-08 15:53:39 +01004366 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004367 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004368 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4369 if (!vif)
4370 return ERR_PTR(-ENOMEM);
4371
4372 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004373 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004374
Arend van Spriel9f440b72013-02-08 15:53:36 +01004375 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004376 vif->pm_block = pm_block;
4377 vif->roam_off = -1;
4378
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004379 brcmf_init_prof(&vif->profile);
4380
Arend van Spriel3eacf862012-10-22 13:55:30 -07004381 list_add_tail(&vif->list, &cfg->vif_list);
4382 cfg->vif_cnt++;
4383 return vif;
4384}
4385
Arend van Spriel24e28be2013-05-27 21:09:55 +02004386void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
4387 struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004388{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004389 list_del(&vif->list);
4390 cfg->vif_cnt--;
4391
4392 kfree(vif);
4393 if (!cfg->vif_cnt) {
Arend van Spriel24e28be2013-05-27 21:09:55 +02004394 wiphy_unregister(cfg->wiphy);
4395 wiphy_free(cfg->wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004396 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004397}
4398
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004399static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004400{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004401 u32 event = e->event_code;
4402 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004403
4404 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004405 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004406 return true;
4407 }
4408
4409 return false;
4410}
4411
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004412static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004413{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004414 u32 event = e->event_code;
4415 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004416
4417 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004418 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004419 return true;
4420 }
4421 return false;
4422}
4423
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004424static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004425 const struct brcmf_event_msg *e)
4426{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004427 u32 event = e->event_code;
4428 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004429
4430 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004431 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4432 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004433 return true;
4434 }
4435
4436 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004437 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004438 return true;
4439 }
4440
4441 return false;
4442}
4443
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004444static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004445{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004446 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004447
4448 kfree(conn_info->req_ie);
4449 conn_info->req_ie = NULL;
4450 conn_info->req_ie_len = 0;
4451 kfree(conn_info->resp_ie);
4452 conn_info->resp_ie = NULL;
4453 conn_info->resp_ie_len = 0;
4454}
4455
Hante Meuleman89286dc2013-02-08 15:53:46 +01004456static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4457 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004458{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004459 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004460 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004461 u32 req_len;
4462 u32 resp_len;
4463 s32 err = 0;
4464
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004465 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004466
Arend van Sprielac24be62012-10-22 10:36:23 -07004467 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4468 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004469 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004470 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004471 return err;
4472 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004473 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004474 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004475 req_len = le32_to_cpu(assoc_info->req_len);
4476 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004477 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004478 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004479 cfg->extra_buf,
4480 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004481 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004482 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004483 return err;
4484 }
4485 conn_info->req_ie_len = req_len;
4486 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004487 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004488 GFP_KERNEL);
4489 } else {
4490 conn_info->req_ie_len = 0;
4491 conn_info->req_ie = NULL;
4492 }
4493 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004494 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004495 cfg->extra_buf,
4496 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004497 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004498 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004499 return err;
4500 }
4501 conn_info->resp_ie_len = resp_len;
4502 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004503 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004504 GFP_KERNEL);
4505 } else {
4506 conn_info->resp_ie_len = 0;
4507 conn_info->resp_ie = NULL;
4508 }
Arend van Spriel16886732012-12-05 15:26:04 +01004509 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4510 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004511
4512 return err;
4513}
4514
4515static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004516brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004517 struct net_device *ndev,
4518 const struct brcmf_event_msg *e)
4519{
Arend van Sprielc1179032012-10-22 13:55:33 -07004520 struct brcmf_if *ifp = netdev_priv(ndev);
4521 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004522 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4523 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004524 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004525 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004526 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004527 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004528 u32 freq;
4529 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004530 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004531
Arend van Sprield96b8012012-12-05 15:26:02 +01004532 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004533
Hante Meuleman89286dc2013-02-08 15:53:46 +01004534 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004535 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004536 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004537
Franky Lina180b832012-10-10 11:13:09 -07004538 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4539 if (buf == NULL) {
4540 err = -ENOMEM;
4541 goto done;
4542 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004543
Franky Lina180b832012-10-10 11:13:09 -07004544 /* data sent to dongle has to be little endian */
4545 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004546 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004547 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004548
4549 if (err)
4550 goto done;
4551
4552 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004553 ch.chspec = le16_to_cpu(bi->chanspec);
4554 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004555
Franky Lin83cf17a2013-04-11 13:28:50 +02004556 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004557 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4558 else
4559 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4560
Franky Lin83cf17a2013-04-11 13:28:50 +02004561 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004562 notify_channel = ieee80211_get_channel(wiphy, freq);
4563
Franky Lina180b832012-10-10 11:13:09 -07004564done:
4565 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004566 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004567 conn_info->req_ie, conn_info->req_ie_len,
4568 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004569 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004570
Arend van Sprielc1179032012-10-22 13:55:33 -07004571 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004572 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004573 return err;
4574}
4575
4576static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004577brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004578 struct net_device *ndev, const struct brcmf_event_msg *e,
4579 bool completed)
4580{
Arend van Sprielc1179032012-10-22 13:55:33 -07004581 struct brcmf_if *ifp = netdev_priv(ndev);
4582 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004583 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004584 s32 err = 0;
4585
Arend van Sprield96b8012012-12-05 15:26:02 +01004586 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004587
Arend van Sprielc1179032012-10-22 13:55:33 -07004588 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4589 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004590 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004591 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004592 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004593 brcmf_update_bss_info(cfg, ifp);
4594 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4595 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004596 }
4597 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004598 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004599 conn_info->req_ie,
4600 conn_info->req_ie_len,
4601 conn_info->resp_ie,
4602 conn_info->resp_ie_len,
4603 completed ? WLAN_STATUS_SUCCESS :
4604 WLAN_STATUS_AUTH_TIMEOUT,
4605 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004606 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4607 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004608 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004609 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004610 return err;
4611}
4612
4613static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004614brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004615 struct net_device *ndev,
4616 const struct brcmf_event_msg *e, void *data)
4617{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004618 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004619 u32 event = e->event_code;
4620 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004621 struct station_info sinfo;
4622
Arend van Spriel16886732012-12-05 15:26:04 +01004623 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004624 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4625 ndev != cfg_to_ndev(cfg)) {
4626 brcmf_dbg(CONN, "AP mode link down\n");
4627 complete(&cfg->vif_disabled);
4628 return 0;
4629 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004630
Hante Meuleman1a873342012-09-27 14:17:54 +02004631 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004632 (reason == BRCMF_E_STATUS_SUCCESS)) {
4633 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004634 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4635 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004636 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004637 return -EINVAL;
4638 }
4639 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004640 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004641 generation++;
4642 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004643 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004644 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4645 (event == BRCMF_E_DEAUTH_IND) ||
4646 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004647 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004648 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004649 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004650}
4651
4652static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004653brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004654 const struct brcmf_event_msg *e, void *data)
4655{
Arend van Spriel19937322012-11-05 16:22:32 -08004656 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4657 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004658 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004659 s32 err = 0;
4660
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004661 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004662 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004663 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004664 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004665 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004666 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004667 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004668 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004669 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4670 &ifp->vif->sme_state);
4671 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4672 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004673 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004674 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004675 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004676 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004677 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004678 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004679 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004680 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004681 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004682 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004683 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004684 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004685 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004686 if (ndev != cfg_to_ndev(cfg))
4687 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004688 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004689 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004690 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4691 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004692 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004693 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004694 }
4695
4696 return err;
4697}
4698
4699static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004700brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004701 const struct brcmf_event_msg *e, void *data)
4702{
Arend van Spriel19937322012-11-05 16:22:32 -08004703 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004704 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004705 u32 event = e->event_code;
4706 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004707
4708 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004709 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004710 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004711 else
Arend van Spriel19937322012-11-05 16:22:32 -08004712 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004713 }
4714
4715 return err;
4716}
4717
4718static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004719brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004720 const struct brcmf_event_msg *e, void *data)
4721{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004722 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004723 enum nl80211_key_type key_type;
4724
4725 if (flags & BRCMF_EVENT_MSG_GROUP)
4726 key_type = NL80211_KEYTYPE_GROUP;
4727 else
4728 key_type = NL80211_KEYTYPE_PAIRWISE;
4729
Arend van Spriel19937322012-11-05 16:22:32 -08004730 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004731 NULL, GFP_KERNEL);
4732
4733 return 0;
4734}
4735
Arend van Sprield3c0b632013-02-08 15:53:37 +01004736static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4737 const struct brcmf_event_msg *e, void *data)
4738{
4739 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4740 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4741 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4742 struct brcmf_cfg80211_vif *vif;
4743
4744 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4745 ifevent->action, ifevent->flags, ifevent->ifidx,
4746 ifevent->bssidx);
4747
Arend van Sprield3c0b632013-02-08 15:53:37 +01004748 mutex_lock(&event->vif_event_lock);
4749 event->action = ifevent->action;
4750 vif = event->vif;
4751
4752 switch (ifevent->action) {
4753 case BRCMF_E_IF_ADD:
4754 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08004755 if (!cfg->vif_event.vif) {
4756 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004757 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08004758 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004759
4760 ifp->vif = vif;
4761 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02004762 if (ifp->ndev) {
4763 vif->wdev.netdev = ifp->ndev;
4764 ifp->ndev->ieee80211_ptr = &vif->wdev;
4765 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4766 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004767 mutex_unlock(&event->vif_event_lock);
4768 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01004769 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004770
4771 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01004772 mutex_unlock(&event->vif_event_lock);
4773 /* event may not be upon user request */
4774 if (brcmf_cfg80211_vif_event_armed(cfg))
4775 wake_up(&event->vif_wq);
4776 return 0;
4777
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01004778 case BRCMF_E_IF_CHANGE:
4779 mutex_unlock(&event->vif_event_lock);
4780 wake_up(&event->vif_wq);
4781 return 0;
4782
Arend van Sprield3c0b632013-02-08 15:53:37 +01004783 default:
4784 mutex_unlock(&event->vif_event_lock);
4785 break;
4786 }
4787 return -EINVAL;
4788}
4789
Arend van Spriel5b435de2011-10-05 13:19:03 +02004790static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4791{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004792 conf->frag_threshold = (u32)-1;
4793 conf->rts_threshold = (u32)-1;
4794 conf->retry_short = (u32)-1;
4795 conf->retry_long = (u32)-1;
4796 conf->tx_power = -1;
4797}
4798
Arend van Spriel5c36b992012-11-14 18:46:05 -08004799static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004800{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004801 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4802 brcmf_notify_connect_status);
4803 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4804 brcmf_notify_connect_status);
4805 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4806 brcmf_notify_connect_status);
4807 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4808 brcmf_notify_connect_status);
4809 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4810 brcmf_notify_connect_status);
4811 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4812 brcmf_notify_connect_status);
4813 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4814 brcmf_notify_roaming_status);
4815 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4816 brcmf_notify_mic_status);
4817 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4818 brcmf_notify_connect_status);
4819 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4820 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004821 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4822 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004823 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004824 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004825 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4826 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01004827 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4828 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004829 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4830 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004831 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4832 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004833}
4834
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004835static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004836{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004837 kfree(cfg->conf);
4838 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004839 kfree(cfg->escan_ioctl_buf);
4840 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004841 kfree(cfg->extra_buf);
4842 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004843 kfree(cfg->pmk_list);
4844 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004845}
4846
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004847static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004848{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004849 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4850 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004851 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004852 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4853 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004854 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004855 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4856 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004857 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004858 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4859 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004860 goto init_priv_mem_out;
4861
4862 return 0;
4863
4864init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004865 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004866
4867 return -ENOMEM;
4868}
4869
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004870static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004871{
4872 s32 err = 0;
4873
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004874 cfg->scan_request = NULL;
4875 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004876 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004877 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004878 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004879 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004880 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004881 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004882 if (err)
4883 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004884 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004885 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004886 brcmf_init_escan(cfg);
4887 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004888 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004889 return err;
4890}
4891
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004892static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004893{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004894 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004895 brcmf_abort_scanning(cfg);
4896 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004897}
4898
Arend van Sprield3c0b632013-02-08 15:53:37 +01004899static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4900{
4901 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004902 mutex_init(&event->vif_event_lock);
4903}
4904
Arend van Sprield9cb2592012-12-05 15:25:54 +01004905struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4906 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004907{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004908 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004909 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004910 struct wiphy *wiphy;
4911 struct brcmf_cfg80211_vif *vif;
4912 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004913 s32 err = 0;
Franky Lin83cf17a2013-04-11 13:28:50 +02004914 s32 io_type;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004915
4916 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004917 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004918 return NULL;
4919 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004920
Arend van Spriel3eacf862012-10-22 13:55:30 -07004921 ifp = netdev_priv(ndev);
4922 wiphy = brcmf_setup_wiphy(busdev);
4923 if (IS_ERR(wiphy))
4924 return NULL;
4925
4926 cfg = wiphy_priv(wiphy);
4927 cfg->wiphy = wiphy;
4928 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004929 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004930 INIT_LIST_HEAD(&cfg->vif_list);
4931
Arend van Sprield3c0b632013-02-08 15:53:37 +01004932 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004933 if (IS_ERR(vif)) {
4934 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004935 return NULL;
4936 }
4937
Arend van Sprield3c0b632013-02-08 15:53:37 +01004938 vif->ifp = ifp;
4939 vif->wdev.netdev = ndev;
4940 ndev->ieee80211_ptr = &vif->wdev;
4941 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4942
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004943 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004944 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004945 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004946 goto cfg80211_attach_out;
4947 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004948 ifp->vif = vif;
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004949
4950 err = brcmf_p2p_attach(cfg);
4951 if (err) {
4952 brcmf_err("P2P initilisation failed (%d)\n", err);
4953 goto cfg80211_p2p_attach_out;
4954 }
Piotr Haber61730d42013-04-23 12:53:12 +02004955 err = brcmf_btcoex_attach(cfg);
4956 if (err) {
4957 brcmf_err("BT-coex initialisation failed (%d)\n", err);
4958 brcmf_p2p_detach(&cfg->p2p);
4959 goto cfg80211_p2p_attach_out;
4960 }
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004961
Arend van Spriel89c2f382013-08-10 12:27:25 +02004962 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
4963 if (err) {
4964 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
4965 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
4966 }
4967
Franky Lin83cf17a2013-04-11 13:28:50 +02004968 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
4969 &io_type);
4970 if (err) {
4971 brcmf_err("Failed to get D11 version (%d)\n", err);
4972 goto cfg80211_p2p_attach_out;
4973 }
4974 cfg->d11inf.io_type = (u8)io_type;
4975 brcmu_d11_attach(&cfg->d11inf);
4976
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004977 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004978
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004979cfg80211_p2p_attach_out:
4980 wl_deinit_priv(cfg);
4981
Arend van Spriel5b435de2011-10-05 13:19:03 +02004982cfg80211_attach_out:
Arend van Spriel24e28be2013-05-27 21:09:55 +02004983 brcmf_free_vif(cfg, vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004984 return NULL;
4985}
4986
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004987void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004988{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004989 struct brcmf_cfg80211_vif *vif;
4990 struct brcmf_cfg80211_vif *tmp;
4991
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004992 wl_deinit_priv(cfg);
Piotr Haber61730d42013-04-23 12:53:12 +02004993 brcmf_btcoex_detach(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004994 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
Arend van Spriel24e28be2013-05-27 21:09:55 +02004995 brcmf_free_vif(cfg, vif);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004996 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004997}
4998
Arend van Spriel5b435de2011-10-05 13:19:03 +02004999static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005000brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005001{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005002 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005003 __le32 roamtrigger[2];
5004 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005005
5006 /*
5007 * Setup timeout if Beacons are lost and roam is
5008 * off to report link down
5009 */
5010 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005011 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005012 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005013 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005014 goto dongle_rom_out;
5015 }
5016 }
5017
5018 /*
5019 * Enable/Disable built-in roaming to allow supplicant
5020 * to take care of roaming
5021 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005022 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07005023 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005024 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005025 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005026 goto dongle_rom_out;
5027 }
5028
Arend van Sprielf588bc02011-10-12 20:51:22 +02005029 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5030 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005031 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005032 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005033 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005034 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005035 goto dongle_rom_out;
5036 }
5037
Arend van Sprielf588bc02011-10-12 20:51:22 +02005038 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5039 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005040 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005041 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005042 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005043 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005044 goto dongle_rom_out;
5045 }
5046
5047dongle_rom_out:
5048 return err;
5049}
5050
5051static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005052brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005053 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005054{
5055 s32 err = 0;
5056
Arend van Sprielac24be62012-10-22 10:36:23 -07005057 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005058 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005059 if (err) {
5060 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005061 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005062 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005063 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005064 goto dongle_scantime_out;
5065 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005066 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005067 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005068 if (err) {
5069 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005070 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005071 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005072 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005073 goto dongle_scantime_out;
5074 }
5075
Arend van Sprielac24be62012-10-22 10:36:23 -07005076 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005077 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005078 if (err) {
5079 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005080 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005081 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005082 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005083 goto dongle_scantime_out;
5084 }
5085
5086dongle_scantime_out:
5087 return err;
5088}
5089
Hante Meulemand48200b2013-04-03 12:40:29 +02005090
Arend van Spriel2375d972014-01-06 12:40:41 +01005091static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
5092 u32 bw_cap[])
Hante Meulemand48200b2013-04-03 12:40:29 +02005093{
5094 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5095 struct ieee80211_channel *band_chan_arr;
5096 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005097 struct brcmu_chan ch;
Hante Meulemand48200b2013-04-03 12:40:29 +02005098 s32 err;
5099 u8 *pbuf;
5100 u32 i, j;
5101 u32 total;
Hante Meulemand48200b2013-04-03 12:40:29 +02005102 enum ieee80211_band band;
5103 u32 channel;
5104 u32 *n_cnt;
Hante Meulemand48200b2013-04-03 12:40:29 +02005105 u32 index;
5106 u32 ht40_flag;
5107 bool update;
5108 u32 array_size;
5109
5110 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5111
5112 if (pbuf == NULL)
5113 return -ENOMEM;
5114
5115 list = (struct brcmf_chanspec_list *)pbuf;
5116
5117 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5118 BRCMF_DCMD_MEDLEN);
5119 if (err) {
5120 brcmf_err("get chanspecs error (%d)\n", err);
5121 goto exit;
5122 }
5123
5124 __wl_band_2ghz.n_channels = 0;
5125 __wl_band_5ghz_a.n_channels = 0;
5126
5127 total = le32_to_cpu(list->count);
5128 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005129 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5130 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005131
Franky Lin83cf17a2013-04-11 13:28:50 +02005132 if (ch.band == BRCMU_CHAN_BAND_2G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005133 band_chan_arr = __wl_2ghz_channels;
5134 array_size = ARRAY_SIZE(__wl_2ghz_channels);
5135 n_cnt = &__wl_band_2ghz.n_channels;
5136 band = IEEE80211_BAND_2GHZ;
Franky Lin83cf17a2013-04-11 13:28:50 +02005137 } else if (ch.band == BRCMU_CHAN_BAND_5G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005138 band_chan_arr = __wl_5ghz_a_channels;
5139 array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
5140 n_cnt = &__wl_band_5ghz_a.n_channels;
5141 band = IEEE80211_BAND_5GHZ;
Hante Meulemand48200b2013-04-03 12:40:29 +02005142 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005143 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005144 continue;
5145 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005146 if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
5147 ch.bw == BRCMU_CHAN_BW_40)
Hante Meulemand48200b2013-04-03 12:40:29 +02005148 continue;
5149 update = false;
5150 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005151 if (band_chan_arr[j].hw_value == ch.chnum) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005152 update = true;
5153 break;
5154 }
5155 }
5156 if (update)
5157 index = j;
5158 else
5159 index = *n_cnt;
5160 if (index < array_size) {
5161 band_chan_arr[index].center_freq =
Franky Lin83cf17a2013-04-11 13:28:50 +02005162 ieee80211_channel_to_frequency(ch.chnum, band);
5163 band_chan_arr[index].hw_value = ch.chnum;
Hante Meulemand48200b2013-04-03 12:40:29 +02005164
Arend van Spriel2375d972014-01-06 12:40:41 +01005165 brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
5166 ch.chnum, band_chan_arr[index].center_freq,
5167 ch.bw, ch.sb);
5168 if (ch.bw == BRCMU_CHAN_BW_40) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005169 /* assuming the order is HT20, HT40 Upper,
5170 * HT40 lower from chanspecs
5171 */
5172 ht40_flag = band_chan_arr[index].flags &
5173 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005174 if (ch.sb == BRCMU_CHAN_SB_U) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005175 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5176 band_chan_arr[index].flags &=
5177 ~IEEE80211_CHAN_NO_HT40;
5178 band_chan_arr[index].flags |=
5179 IEEE80211_CHAN_NO_HT40PLUS;
5180 } else {
5181 /* It should be one of
5182 * IEEE80211_CHAN_NO_HT40 or
5183 * IEEE80211_CHAN_NO_HT40PLUS
5184 */
5185 band_chan_arr[index].flags &=
5186 ~IEEE80211_CHAN_NO_HT40;
5187 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5188 band_chan_arr[index].flags |=
5189 IEEE80211_CHAN_NO_HT40MINUS;
5190 }
5191 } else {
5192 band_chan_arr[index].flags =
5193 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005194 ch.bw = BRCMU_CHAN_BW_20;
5195 cfg->d11inf.encchspec(&ch);
5196 channel = ch.chspec;
Hante Meulemand48200b2013-04-03 12:40:29 +02005197 err = brcmf_fil_bsscfg_int_get(ifp,
5198 "per_chan_info",
5199 &channel);
5200 if (!err) {
5201 if (channel & WL_CHAN_RADAR)
5202 band_chan_arr[index].flags |=
5203 (IEEE80211_CHAN_RADAR |
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005204 IEEE80211_CHAN_NO_IR);
Hante Meulemand48200b2013-04-03 12:40:29 +02005205 if (channel & WL_CHAN_PASSIVE)
5206 band_chan_arr[index].flags |=
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005207 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005208 }
5209 }
5210 if (!update)
5211 (*n_cnt)++;
5212 }
5213 }
5214exit:
5215 kfree(pbuf);
5216 return err;
5217}
5218
Arend van Spriel2375d972014-01-06 12:40:41 +01005219static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
5220{
5221 u32 band, mimo_bwcap;
5222 int err;
5223
5224 band = WLC_BAND_2G;
5225 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5226 if (!err) {
5227 bw_cap[IEEE80211_BAND_2GHZ] = band;
5228 band = WLC_BAND_5G;
5229 err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
5230 if (!err) {
5231 bw_cap[IEEE80211_BAND_5GHZ] = band;
5232 return;
5233 }
5234 WARN_ON(1);
5235 return;
5236 }
5237 brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
5238 mimo_bwcap = 0;
5239 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
5240 if (err)
5241 /* assume 20MHz if firmware does not give a clue */
5242 mimo_bwcap = WLC_N_BW_20ALL;
5243
5244 switch (mimo_bwcap) {
5245 case WLC_N_BW_40ALL:
5246 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
5247 /* fall-thru */
5248 case WLC_N_BW_20IN2G_40IN5G:
5249 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
5250 /* fall-thru */
5251 case WLC_N_BW_20ALL:
5252 bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
5253 bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
5254 break;
5255 default:
5256 brcmf_err("invalid mimo_bw_cap value\n");
5257 }
5258}
Hante Meulemand48200b2013-04-03 12:40:29 +02005259
5260static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005261{
Arend van Sprielac24be62012-10-22 10:36:23 -07005262 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005263 struct wiphy *wiphy;
5264 s32 phy_list;
Hante Meulemand48200b2013-04-03 12:40:29 +02005265 u32 band_list[3];
5266 u32 nmode;
Arend van Spriel2375d972014-01-06 12:40:41 +01005267 u32 bw_cap[2] = { 0, 0 };
Arend van Spriel5b435de2011-10-05 13:19:03 +02005268 s8 phy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005269 s32 err;
5270 u32 nband;
5271 s32 i;
Arend van Spriel2375d972014-01-06 12:40:41 +01005272 struct ieee80211_supported_band *bands[2] = { NULL, NULL };
5273 struct ieee80211_supported_band *band;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005274
Hante Meulemanb87e2c42012-11-14 18:46:23 -08005275 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005276 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005277 if (err) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005278 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005279 return err;
5280 }
5281
Hante Meuleman3ba81372012-09-19 22:21:13 +02005282 phy = ((char *)&phy_list)[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005283 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5284
5285
5286 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5287 &band_list, sizeof(band_list));
5288 if (err) {
5289 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5290 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005291 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005292 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5293 band_list[0], band_list[1], band_list[2]);
5294
5295 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5296 if (err) {
5297 brcmf_err("nmode error (%d)\n", err);
5298 } else {
Arend van Spriel2375d972014-01-06 12:40:41 +01005299 brcmf_get_bwcap(ifp, bw_cap);
Hante Meulemand48200b2013-04-03 12:40:29 +02005300 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005301 brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
5302 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
Hante Meulemand48200b2013-04-03 12:40:29 +02005303
5304 err = brcmf_construct_reginfo(cfg, bw_cap);
5305 if (err) {
5306 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5307 return err;
5308 }
5309
5310 nband = band_list[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005311
5312 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
Arend van Spriel2375d972014-01-06 12:40:41 +01005313 band = NULL;
Hante Meulemand48200b2013-04-03 12:40:29 +02005314 if ((band_list[i] == WLC_BAND_5G) &&
Arend van Spriel2375d972014-01-06 12:40:41 +01005315 (__wl_band_5ghz_a.n_channels > 0))
5316 band = &__wl_band_5ghz_a;
5317 else if ((band_list[i] == WLC_BAND_2G) &&
5318 (__wl_band_2ghz.n_channels > 0))
5319 band = &__wl_band_2ghz;
5320 else
5321 continue;
Hante Meulemand48200b2013-04-03 12:40:29 +02005322
Arend van Spriel2375d972014-01-06 12:40:41 +01005323 if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
5324 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
5325 band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
Hante Meulemand48200b2013-04-03 12:40:29 +02005326 }
Arend van Spriel2375d972014-01-06 12:40:41 +01005327 band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5328 band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5329 band->ht_cap.ht_supported = true;
5330 band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
5331 band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
5332 /* An HT shall support all EQM rates for one spatial
5333 * stream
5334 */
5335 band->ht_cap.mcs.rx_mask[0] = 0xff;
5336 band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
5337 bands[band->band] = band;
Hante Meulemand48200b2013-04-03 12:40:29 +02005338 }
5339
5340 wiphy = cfg_to_wiphy(cfg);
5341 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5342 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5343 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005344
5345 return err;
5346}
5347
Hante Meulemand48200b2013-04-03 12:40:29 +02005348
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005349static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005350{
Hante Meulemand48200b2013-04-03 12:40:29 +02005351 return brcmf_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005352}
5353
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005354static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005355{
5356 struct net_device *ndev;
5357 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01005358 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005359 s32 power_mode;
5360 s32 err = 0;
5361
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005362 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005363 return err;
5364
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005365 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005366 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01005367 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368
Hante Meuleman40a23292013-01-02 15:22:51 +01005369 /* make sure RF is ready for work */
5370 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5371
5372 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5373 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005374
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005375 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01005376 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005377 if (err)
5378 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005379 brcmf_dbg(INFO, "power save set to %s\n",
5380 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005381
Hante Meuleman40a23292013-01-02 15:22:51 +01005382 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005383 if (err)
5384 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07005385 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5386 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01005387 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005388 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005389 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005390 if (err)
5391 goto default_conf_out;
5392
Hante Meulemanb3657452013-05-27 21:09:53 +02005393 brcmf_configure_arp_offload(ifp, true);
5394
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005395 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01005396default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005397
5398 return err;
5399
5400}
5401
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005402static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005403{
Arend van Sprielc1179032012-10-22 13:55:33 -07005404 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005405
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005406 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005407}
5408
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005409static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005410{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005411 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07005412
Arend van Spriel5b435de2011-10-05 13:19:03 +02005413 /*
5414 * While going down, if associated with AP disassociate
5415 * from AP to save power
5416 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005417 if (check_vif_up(ifp->vif)) {
5418 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005419
5420 /* Make sure WPA_Supplicant receives all the event
5421 generated due to DISASSOC call to the fw to keep
5422 the state fw and WPA_Supplicant state consistent
5423 */
5424 brcmf_delay(500);
5425 }
5426
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005427 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005428 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005429
Arend van Spriel5b435de2011-10-05 13:19:03 +02005430 return 0;
5431}
5432
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005433s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005434{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005435 struct brcmf_if *ifp = netdev_priv(ndev);
5436 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005437 s32 err = 0;
5438
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005439 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005440 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005441 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005442
5443 return err;
5444}
5445
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005446s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005447{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005448 struct brcmf_if *ifp = netdev_priv(ndev);
5449 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005450 s32 err = 0;
5451
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005452 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005453 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005454 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005455
5456 return err;
5457}
5458
Arend van Spriela7965fb2013-04-11 17:08:37 +02005459enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5460{
5461 struct wireless_dev *wdev = &ifp->vif->wdev;
5462
5463 return wdev->iftype;
5464}
5465
Arend van Spriel9f440b72013-02-08 15:53:36 +01005466u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5467{
5468 struct brcmf_cfg80211_vif *vif;
5469 bool result = 0;
5470
5471 list_for_each_entry(vif, &cfg->vif_list, list) {
5472 if (test_bit(state, &vif->sme_state))
5473 result++;
5474 }
5475 return result;
5476}
Arend van Sprield3c0b632013-02-08 15:53:37 +01005477
5478static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5479 u8 action)
5480{
5481 u8 evt_action;
5482
5483 mutex_lock(&event->vif_event_lock);
5484 evt_action = event->action;
5485 mutex_unlock(&event->vif_event_lock);
5486 return evt_action == action;
5487}
5488
5489void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5490 struct brcmf_cfg80211_vif *vif)
5491{
5492 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5493
5494 mutex_lock(&event->vif_event_lock);
5495 event->vif = vif;
5496 event->action = 0;
5497 mutex_unlock(&event->vif_event_lock);
5498}
5499
5500bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5501{
5502 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5503 bool armed;
5504
5505 mutex_lock(&event->vif_event_lock);
5506 armed = event->vif != NULL;
5507 mutex_unlock(&event->vif_event_lock);
5508
5509 return armed;
5510}
5511int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5512 u8 action, ulong timeout)
5513{
5514 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5515
5516 return wait_event_timeout(event->vif_wq,
5517 vif_event_equals(event, action), timeout);
5518}
5519