blob: f0bdfb1206676fc2a17356deff4632410c6cef44 [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 cfg80211_disconnected(vif->wdev.netdev, 0,
1099 NULL, 0, GFP_KERNEL);
1100 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001101 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
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 Spriel5b435de2011-10-05 13:19:03 +02001761
Arend van Spriel06bb1232012-09-27 14:17:56 +02001762 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001764 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001765 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001766 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001767 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001768
Arend van Sprield96b8012012-12-05 15:26:02 +01001769 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770 return err;
1771}
1772
1773static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001774brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001775 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001776{
1777
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001778 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001779 struct net_device *ndev = cfg_to_ndev(cfg);
1780 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001781 u16 txpwrmw;
1782 s32 err = 0;
1783 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001784 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001785
Arend van Sprield96b8012012-12-05 15:26:02 +01001786 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001787 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001788 return -EIO;
1789
1790 switch (type) {
1791 case NL80211_TX_POWER_AUTOMATIC:
1792 break;
1793 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001794 case NL80211_TX_POWER_FIXED:
1795 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001796 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001797 err = -EINVAL;
1798 goto done;
1799 }
1800 break;
1801 }
1802 /* Make sure radio is off or on as far as software is concerned */
1803 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001804 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001805 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001806 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001807
1808 if (dbm > 0xffff)
1809 txpwrmw = 0xffff;
1810 else
1811 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001812 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1813 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001814 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001815 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001816 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001817
1818done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001819 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001820 return err;
1821}
1822
Johannes Bergc8442112012-10-24 10:17:18 +02001823static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1824 struct wireless_dev *wdev,
1825 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001826{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001827 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001828 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001829 s32 txpwrdbm;
1830 u8 result;
1831 s32 err = 0;
1832
Arend van Sprield96b8012012-12-05 15:26:02 +01001833 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001834 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001835 return -EIO;
1836
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001837 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001838 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001839 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840 goto done;
1841 }
1842
1843 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001844 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001845
1846done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001847 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001848 return err;
1849}
1850
1851static s32
1852brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1853 u8 key_idx, bool unicast, bool multicast)
1854{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001855 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001856 u32 index;
1857 u32 wsec;
1858 s32 err = 0;
1859
Arend van Sprield96b8012012-12-05 15:26:02 +01001860 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001861 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001862 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001863 return -EIO;
1864
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001865 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001866 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001867 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001868 goto done;
1869 }
1870
1871 if (wsec & WEP_ENABLED) {
1872 /* Just select a new current key */
1873 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001874 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001875 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001876 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001877 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001878 }
1879done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001880 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001881 return err;
1882}
1883
1884static s32
1885brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1886 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1887{
Hante Meuleman992f6062013-04-02 21:06:17 +02001888 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001889 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001890 s32 err = 0;
Hante Meuleman992f6062013-04-02 21:06:17 +02001891 u8 keybuf[8];
Arend van Spriel5b435de2011-10-05 13:19:03 +02001892
1893 memset(&key, 0, sizeof(key));
1894 key.index = (u32) key_idx;
1895 /* Instead of bcast for ea address for default wep keys,
1896 driver needs it to be Null */
1897 if (!is_multicast_ether_addr(mac_addr))
1898 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1899 key.len = (u32) params->key_len;
1900 /* check for key index change */
1901 if (key.len == 0) {
1902 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001903 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001904 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001905 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001906 } else {
1907 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001908 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001909 return -EINVAL;
1910 }
1911
Arend van Spriel16886732012-12-05 15:26:04 +01001912 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001913 memcpy(key.data, params->key, key.len);
1914
Hante Meuleman992f6062013-04-02 21:06:17 +02001915 if ((ifp->vif->mode != WL_MODE_AP) &&
1916 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
1917 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001918 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1919 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1920 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1921 }
1922
1923 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1924 if (params->seq && params->seq_len == 6) {
1925 /* rx iv */
1926 u8 *ivptr;
1927 ivptr = (u8 *) params->seq;
1928 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1929 (ivptr[3] << 8) | ivptr[2];
1930 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1931 key.iv_initialized = true;
1932 }
1933
1934 switch (params->cipher) {
1935 case WLAN_CIPHER_SUITE_WEP40:
1936 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001937 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001938 break;
1939 case WLAN_CIPHER_SUITE_WEP104:
1940 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001941 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001942 break;
1943 case WLAN_CIPHER_SUITE_TKIP:
1944 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001945 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001946 break;
1947 case WLAN_CIPHER_SUITE_AES_CMAC:
1948 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001949 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950 break;
1951 case WLAN_CIPHER_SUITE_CCMP:
1952 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001953 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001954 break;
1955 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001956 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957 return -EINVAL;
1958 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001959 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001960 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001961 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001962 }
1963 return err;
1964}
1965
1966static s32
1967brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1968 u8 key_idx, bool pairwise, const u8 *mac_addr,
1969 struct key_params *params)
1970{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001971 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001972 struct brcmf_wsec_key key;
1973 s32 val;
1974 s32 wsec;
1975 s32 err = 0;
1976 u8 keybuf[8];
1977
Arend van Sprield96b8012012-12-05 15:26:02 +01001978 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001979 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001980 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001981 return -EIO;
1982
1983 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001984 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1986 }
1987 memset(&key, 0, sizeof(key));
1988
1989 key.len = (u32) params->key_len;
1990 key.index = (u32) key_idx;
1991
1992 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001993 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001994 err = -EINVAL;
1995 goto done;
1996 }
1997 memcpy(key.data, params->key, key.len);
1998
1999 key.flags = BRCMF_PRIMARY_KEY;
2000 switch (params->cipher) {
2001 case WLAN_CIPHER_SUITE_WEP40:
2002 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002003 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002004 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002005 break;
2006 case WLAN_CIPHER_SUITE_WEP104:
2007 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002008 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002009 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002010 break;
2011 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002012 if (ifp->vif->mode != WL_MODE_AP) {
Hante Meuleman992f6062013-04-02 21:06:17 +02002013 brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02002014 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2015 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2016 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2017 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002018 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002019 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002020 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002021 break;
2022 case WLAN_CIPHER_SUITE_AES_CMAC:
2023 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002024 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002025 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002026 break;
2027 case WLAN_CIPHER_SUITE_CCMP:
2028 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002029 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002030 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002031 break;
2032 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002033 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002034 err = -EINVAL;
2035 goto done;
2036 }
2037
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002038 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002039 if (err)
2040 goto done;
2041
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002042 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002043 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002044 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002045 goto done;
2046 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002047 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002048 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002049 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002050 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002051 goto done;
2052 }
2053
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002055 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056 return err;
2057}
2058
2059static s32
2060brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2061 u8 key_idx, bool pairwise, const u8 *mac_addr)
2062{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002063 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064 struct brcmf_wsec_key key;
2065 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002066
Arend van Sprield96b8012012-12-05 15:26:02 +01002067 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002068 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069 return -EIO;
2070
Hante Meuleman256c3742012-11-05 16:22:28 -08002071 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2072 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01002073 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08002074 return -EINVAL;
2075 }
2076
Arend van Spriel5b435de2011-10-05 13:19:03 +02002077 memset(&key, 0, sizeof(key));
2078
2079 key.index = (u32) key_idx;
2080 key.flags = BRCMF_PRIMARY_KEY;
2081 key.algo = CRYPTO_ALGO_OFF;
2082
Arend van Spriel16886732012-12-05 15:26:04 +01002083 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002084
2085 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002086 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002087
Arend van Sprield96b8012012-12-05 15:26:02 +01002088 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089 return err;
2090}
2091
2092static s32
2093brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2094 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2095 void (*callback) (void *cookie, struct key_params * params))
2096{
2097 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002098 struct brcmf_if *ifp = netdev_priv(ndev);
2099 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 struct brcmf_cfg80211_security *sec;
2101 s32 wsec;
2102 s32 err = 0;
2103
Arend van Sprield96b8012012-12-05 15:26:02 +01002104 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002105 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002106 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002107 return -EIO;
2108
2109 memset(&params, 0, sizeof(params));
2110
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002111 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002112 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002113 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002114 /* Ignore this error, may happen during DISASSOC */
2115 err = -EAGAIN;
2116 goto done;
2117 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002118 if (wsec & WEP_ENABLED) {
Arend van Spriel06bb1232012-09-27 14:17:56 +02002119 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2121 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002122 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2124 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002125 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002126 }
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002127 } else if (wsec & TKIP_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002128 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002129 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002130 } else if (wsec & AES_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002131 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002132 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Hante Meulemanc5bf53a2013-04-02 21:06:19 +02002133 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002134 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135 err = -EINVAL;
2136 goto done;
2137 }
2138 callback(cookie, &params);
2139
2140done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002141 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142 return err;
2143}
2144
2145static s32
2146brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2147 struct net_device *ndev, u8 key_idx)
2148{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002149 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002150
2151 return -EOPNOTSUPP;
2152}
2153
2154static s32
2155brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002156 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002157{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002158 struct brcmf_if *ifp = netdev_priv(ndev);
2159 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 struct brcmf_scb_val_le scb_val;
2161 int rssi;
2162 s32 rate;
2163 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002164 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002165 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002166
Arend van Sprield96b8012012-12-05 15:26:02 +01002167 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002168 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002169 return -EIO;
2170
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002171 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002172 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002173 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002174 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002175 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002176 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002177 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002178 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002179 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002180 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002181 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2182 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002183 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002184 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002185 }
Arend van Sprield96b8012012-12-05 15:26:02 +01002186 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2187 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002188 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002189 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002190 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2191 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02002192 err = -ENOENT;
2193 goto done;
2194 }
2195 /* Report the current tx rate */
Hante Meuleman89286dc2013-02-08 15:53:46 +01002196 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002197 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002198 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002199 goto done;
2200 } else {
2201 sinfo->filled |= STATION_INFO_TX_BITRATE;
2202 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002203 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002204 }
2205
Arend van Sprielc1179032012-10-22 13:55:33 -07002206 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2207 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002208 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002209 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2210 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002211 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002212 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002213 goto done;
2214 } else {
2215 rssi = le32_to_cpu(scb_val.val);
2216 sinfo->filled |= STATION_INFO_SIGNAL;
2217 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002218 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002219 }
2220 }
2221 } else
2222 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002223done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002224 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002225 return err;
2226}
2227
2228static s32
2229brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2230 bool enabled, s32 timeout)
2231{
2232 s32 pm;
2233 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002234 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002235 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002236
Arend van Sprield96b8012012-12-05 15:26:02 +01002237 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238
2239 /*
2240 * Powersave enable/disable request is coming from the
2241 * cfg80211 even before the interface is up. In that
2242 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002243 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002244 * FW later while initializing the dongle
2245 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002246 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002247 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002248
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002249 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002250 goto done;
2251 }
2252
2253 pm = enabled ? PM_FAST : PM_OFF;
Hante Meuleman102fd0d2013-05-27 21:09:59 +02002254 /* Do not enable the power save after assoc if it is a p2p interface */
2255 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
2256 brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
2257 pm = PM_OFF;
2258 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002259 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260
Arend van Sprielc1179032012-10-22 13:55:33 -07002261 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002262 if (err) {
2263 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002264 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002265 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002266 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267 }
2268done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002269 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002270 return err;
2271}
2272
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002273static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002274 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002276 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277 struct ieee80211_channel *notify_channel;
2278 struct cfg80211_bss *bss;
2279 struct ieee80211_supported_band *band;
Franky Lin83cf17a2013-04-11 13:28:50 +02002280 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002281 s32 err = 0;
2282 u16 channel;
2283 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284 u16 notify_capability;
2285 u16 notify_interval;
2286 u8 *notify_ie;
2287 size_t notify_ielen;
2288 s32 notify_signal;
2289
2290 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002291 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002292 return 0;
2293 }
2294
Franky Lin83cf17a2013-04-11 13:28:50 +02002295 if (!bi->ctl_ch) {
2296 ch.chspec = le16_to_cpu(bi->chanspec);
2297 cfg->d11inf.decchspec(&ch);
2298 bi->ctl_ch = ch.chnum;
2299 }
2300 channel = bi->ctl_ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301
2302 if (channel <= CH_MAX_2G_CHANNEL)
2303 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2304 else
2305 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2306
2307 freq = ieee80211_channel_to_frequency(channel, band->band);
2308 notify_channel = ieee80211_get_channel(wiphy, freq);
2309
Arend van Spriel5b435de2011-10-05 13:19:03 +02002310 notify_capability = le16_to_cpu(bi->capability);
2311 notify_interval = le16_to_cpu(bi->beacon_period);
2312 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2313 notify_ielen = le32_to_cpu(bi->ie_length);
2314 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2315
Arend van Spriel16886732012-12-05 15:26:04 +01002316 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2317 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2318 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2319 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2320 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002321
2322 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002323 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002324 notify_ielen, notify_signal, GFP_KERNEL);
2325
Franky Line78946e2011-11-10 20:30:34 +01002326 if (!bss)
2327 return -ENOMEM;
2328
Johannes Berg5b112d32013-02-01 01:49:58 +01002329 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002330
2331 return err;
2332}
2333
Roland Vossen6f09be02011-10-18 14:03:02 +02002334static struct brcmf_bss_info_le *
2335next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2336{
2337 if (bss == NULL)
2338 return list->bss_info_le;
2339 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2340 le32_to_cpu(bss->length));
2341}
2342
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002343static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344{
2345 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002346 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002347 s32 err = 0;
2348 int i;
2349
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002350 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002351 if (bss_list->count != 0 &&
2352 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002353 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2354 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002355 return -EOPNOTSUPP;
2356 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002357 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002358 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002359 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002360 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002361 if (err)
2362 break;
2363 }
2364 return err;
2365}
2366
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002367static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002368 struct net_device *ndev, const u8 *bssid)
2369{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002370 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002371 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002372 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002373 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002374 struct cfg80211_bss *bss;
Franky Lin83cf17a2013-04-11 13:28:50 +02002375 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376 u8 *buf = NULL;
2377 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002379 u16 notify_capability;
2380 u16 notify_interval;
2381 u8 *notify_ie;
2382 size_t notify_ielen;
2383 s32 notify_signal;
2384
Arend van Sprield96b8012012-12-05 15:26:02 +01002385 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386
2387 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2388 if (buf == NULL) {
2389 err = -ENOMEM;
2390 goto CleanUp;
2391 }
2392
2393 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2394
Arend van Sprielac24be62012-10-22 10:36:23 -07002395 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2396 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002397 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002398 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002399 goto CleanUp;
2400 }
2401
Roland Vossend34bf642011-10-18 14:03:01 +02002402 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002403
Franky Lin83cf17a2013-04-11 13:28:50 +02002404 ch.chspec = le16_to_cpu(bi->chanspec);
2405 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002406
Franky Lin83cf17a2013-04-11 13:28:50 +02002407 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002408 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2409 else
2410 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2411
Franky Lin83cf17a2013-04-11 13:28:50 +02002412 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002413 notify_channel = ieee80211_get_channel(wiphy, freq);
2414
Arend van Spriel5b435de2011-10-05 13:19:03 +02002415 notify_capability = le16_to_cpu(bi->capability);
2416 notify_interval = le16_to_cpu(bi->beacon_period);
2417 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2418 notify_ielen = le32_to_cpu(bi->ie_length);
2419 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2420
Franky Lin83cf17a2013-04-11 13:28:50 +02002421 brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
Arend van Spriel16886732012-12-05 15:26:04 +01002422 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2423 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2424 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425
Franky Line78946e2011-11-10 20:30:34 +01002426 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002427 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002428 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2429
Franky Line78946e2011-11-10 20:30:34 +01002430 if (!bss) {
2431 err = -ENOMEM;
2432 goto CleanUp;
2433 }
2434
Johannes Berg5b112d32013-02-01 01:49:58 +01002435 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002436
Arend van Spriel5b435de2011-10-05 13:19:03 +02002437CleanUp:
2438
2439 kfree(buf);
2440
Arend van Sprield96b8012012-12-05 15:26:02 +01002441 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002442
2443 return err;
2444}
2445
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002446static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002447{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002448 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002449}
2450
Hante Meuleman89286dc2013-02-08 15:53:46 +01002451static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2452 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002453{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002454 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002455 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002456 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002457 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002458 u16 beacon_interval;
2459 u8 dtim_period;
2460 size_t ie_len;
2461 u8 *ie;
2462 s32 err = 0;
2463
Arend van Sprield96b8012012-12-05 15:26:02 +01002464 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002465 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002466 return err;
2467
Arend van Spriel06bb1232012-09-27 14:17:56 +02002468 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002469
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002470 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002471 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002472 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002473 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002474 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002475 goto update_bss_info_out;
2476 }
2477
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002478 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2479 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002480 if (err)
2481 goto update_bss_info_out;
2482
2483 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2484 ie_len = le32_to_cpu(bi->ie_length);
2485 beacon_interval = le16_to_cpu(bi->beacon_period);
2486
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002487 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002488 if (tim)
2489 dtim_period = tim->data[1];
2490 else {
2491 /*
2492 * active scan was done so we could not get dtim
2493 * information out of probe response.
2494 * so we speficially query dtim information to dongle.
2495 */
2496 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002497 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002498 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002499 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002500 goto update_bss_info_out;
2501 }
2502 dtim_period = (u8)var;
2503 }
2504
Arend van Spriel5b435de2011-10-05 13:19:03 +02002505update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002506 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002507 return err;
2508}
2509
Hante Meuleman18e2f612013-02-08 15:53:49 +01002510void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002511{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002512 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002513
Arend van Sprielc1179032012-10-22 13:55:33 -07002514 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002515 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002516 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002517 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002518 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002519 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2520 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002521}
2522
Hante Meulemane756af52012-09-11 21:18:52 +02002523static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2524{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002525 struct brcmf_cfg80211_info *cfg =
2526 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002527 escan_timeout_work);
2528
Arend van Spriela0f472a2013-04-05 10:57:49 +02002529 brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002530}
2531
2532static void brcmf_escan_timeout(unsigned long data)
2533{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002534 struct brcmf_cfg80211_info *cfg =
2535 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002536
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002537 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002538 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002539 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002540 }
2541}
2542
2543static s32
Franky Lin83cf17a2013-04-11 13:28:50 +02002544brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
2545 struct brcmf_bss_info_le *bss,
Hante Meulemane756af52012-09-11 21:18:52 +02002546 struct brcmf_bss_info_le *bss_info_le)
2547{
Franky Lin83cf17a2013-04-11 13:28:50 +02002548 struct brcmu_chan ch_bss, ch_bss_info_le;
2549
2550 ch_bss.chspec = le16_to_cpu(bss->chanspec);
2551 cfg->d11inf.decchspec(&ch_bss);
2552 ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
2553 cfg->d11inf.decchspec(&ch_bss_info_le);
2554
Hante Meulemane756af52012-09-11 21:18:52 +02002555 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
Franky Lin83cf17a2013-04-11 13:28:50 +02002556 ch_bss.band == ch_bss_info_le.band &&
Hante Meulemane756af52012-09-11 21:18:52 +02002557 bss_info_le->SSID_len == bss->SSID_len &&
2558 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2559 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2560 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002561 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2562 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2563
Hante Meulemane756af52012-09-11 21:18:52 +02002564 /* preserve max RSSI if the measurements are
2565 * both on-channel or both off-channel
2566 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002567 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002568 bss->RSSI = bss_info_le->RSSI;
2569 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2570 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2571 /* preserve the on-channel rssi measurement
2572 * if the new measurement is off channel
2573 */
2574 bss->RSSI = bss_info_le->RSSI;
2575 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2576 }
2577 return 1;
2578 }
2579 return 0;
2580}
2581
2582static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002583brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002584 const struct brcmf_event_msg *e, void *data)
2585{
Arend van Spriel19937322012-11-05 16:22:32 -08002586 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Hante Meulemane756af52012-09-11 21:18:52 +02002587 s32 status;
2588 s32 err = 0;
2589 struct brcmf_escan_result_le *escan_result_le;
2590 struct brcmf_bss_info_le *bss_info_le;
2591 struct brcmf_bss_info_le *bss = NULL;
2592 u32 bi_length;
2593 struct brcmf_scan_results *list;
2594 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002595 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002596
Arend van Spriel5c36b992012-11-14 18:46:05 -08002597 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002598
Arend van Spriela0f472a2013-04-05 10:57:49 +02002599 if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2600 brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
Hante Meulemane756af52012-09-11 21:18:52 +02002601 return -EPERM;
2602 }
2603
2604 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002605 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002606 escan_result_le = (struct brcmf_escan_result_le *) data;
2607 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002608 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002609 goto exit;
2610 }
Hante Meulemane756af52012-09-11 21:18:52 +02002611 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002612 brcmf_err("Invalid bss_count %d: ignoring\n",
2613 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002614 goto exit;
2615 }
2616 bss_info_le = &escan_result_le->bss_info_le;
2617
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002618 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2619 goto exit;
2620
2621 if (!cfg->scan_request) {
2622 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2623 goto exit;
2624 }
2625
Hante Meulemane756af52012-09-11 21:18:52 +02002626 bi_length = le32_to_cpu(bss_info_le->length);
2627 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2628 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002629 brcmf_err("Invalid bss_info length %d: ignoring\n",
2630 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002631 goto exit;
2632 }
2633
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002634 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002635 BIT(NL80211_IFTYPE_ADHOC))) {
2636 if (le16_to_cpu(bss_info_le->capability) &
2637 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002638 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002639 goto exit;
2640 }
2641 }
2642
2643 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002644 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002645 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002646 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002647 goto exit;
2648 }
2649
2650 for (i = 0; i < list->count; i++) {
2651 bss = bss ? (struct brcmf_bss_info_le *)
2652 ((unsigned char *)bss +
2653 le32_to_cpu(bss->length)) : list->bss_info_le;
Franky Lin83cf17a2013-04-11 13:28:50 +02002654 if (brcmf_compare_update_same_bss(cfg, bss,
2655 bss_info_le))
Hante Meulemane756af52012-09-11 21:18:52 +02002656 goto exit;
2657 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002658 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002659 bss_info_le, bi_length);
2660 list->version = le32_to_cpu(bss_info_le->version);
2661 list->buflen += bi_length;
2662 list->count++;
2663 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002664 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002665 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2666 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002667 if (cfg->scan_request) {
2668 cfg->bss_list = (struct brcmf_scan_results *)
2669 cfg->escan_info.escan_buf;
2670 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002671 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriela0f472a2013-04-05 10:57:49 +02002672 brcmf_notify_escan_complete(cfg, ifp, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002673 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002674 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002675 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2676 status);
Hante Meulemane756af52012-09-11 21:18:52 +02002677 }
2678exit:
2679 return err;
2680}
2681
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002682static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002683{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002684 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2685 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002686 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2687 /* Init scan_timeout timer */
2688 init_timer(&cfg->escan_timeout);
2689 cfg->escan_timeout.data = (unsigned long) cfg;
2690 cfg->escan_timeout.function = brcmf_escan_timeout;
2691 INIT_WORK(&cfg->escan_timeout_work,
2692 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002693}
2694
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002695static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002696{
2697 if (ms < 1000 / HZ) {
2698 cond_resched();
2699 mdelay(ms);
2700 } else {
2701 msleep(ms);
2702 }
2703}
2704
2705static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2706{
Arend van Sprield96b8012012-12-05 15:26:02 +01002707 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002708
Arend van Spriel5b435de2011-10-05 13:19:03 +02002709 return 0;
2710}
2711
2712static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2713 struct cfg80211_wowlan *wow)
2714{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002715 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2716 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002717 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718
Arend van Sprield96b8012012-12-05 15:26:02 +01002719 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002720
2721 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002722 * if the primary net_device is not READY there is nothing
2723 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002724 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002725 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2726 if (!check_vif_up(vif))
2727 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002728
Arend van Spriel7d641072012-10-22 13:55:39 -07002729 list_for_each_entry(vif, &cfg->vif_list, list) {
2730 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2731 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002732 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002733 * While going to suspend if associated with AP disassociate
2734 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002735 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002736 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002737
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002738 /* Make sure WPA_Supplicant receives all the event
2739 * generated due to DISASSOC call to the fw to keep
2740 * the state fw and WPA_Supplicant state consistent
2741 */
2742 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002743 }
2744
Arend van Spriel7d641072012-10-22 13:55:39 -07002745 /* end any scanning */
2746 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002747 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002748
2749 /* Turn off watchdog timer */
Arend van Sprielf96aa072013-04-05 10:57:48 +02002750 brcmf_set_mpc(netdev_priv(ndev), 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002751
Arend van Spriel7d641072012-10-22 13:55:39 -07002752exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002753 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002754 /* clear any scanning activity */
2755 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756 return 0;
2757}
2758
2759static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002760brcmf_update_pmklist(struct net_device *ndev,
2761 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2762{
2763 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002764 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002765
Arend van Spriel40c8e952011-10-12 20:51:20 +02002766 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2767
Arend van Spriel16886732012-12-05 15:26:04 +01002768 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002769 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002770 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2771 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002773 brcmf_dbg(CONN, "%02x\n",
2774 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002775 }
2776
2777 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002778 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2779 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002780
2781 return err;
2782}
2783
2784static s32
2785brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2786 struct cfg80211_pmksa *pmksa)
2787{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002788 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002789 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002790 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002791 s32 err = 0;
2792 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002793 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002794
Arend van Sprield96b8012012-12-05 15:26:02 +01002795 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002796 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002797 return -EIO;
2798
Arend van Spriel40c8e952011-10-12 20:51:20 +02002799 pmkid_len = le32_to_cpu(pmkids->npmkid);
2800 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002801 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2802 break;
2803 if (i < WL_NUM_PMKIDS_MAX) {
2804 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2805 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002806 if (i == pmkid_len) {
2807 pmkid_len++;
2808 pmkids->npmkid = cpu_to_le32(pmkid_len);
2809 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002810 } else
2811 err = -EINVAL;
2812
Arend van Spriel16886732012-12-05 15:26:04 +01002813 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2814 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002815 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002816 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002817
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002818 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002819
Arend van Sprield96b8012012-12-05 15:26:02 +01002820 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002821 return err;
2822}
2823
2824static s32
2825brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2826 struct cfg80211_pmksa *pmksa)
2827{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002828 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002829 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002830 struct pmkid_list pmkid;
2831 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002832 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002833
Arend van Sprield96b8012012-12-05 15:26:02 +01002834 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002835 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002836 return -EIO;
2837
2838 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2839 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2840
Arend van Spriel16886732012-12-05 15:26:04 +01002841 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2842 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002843 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002844 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002845
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002846 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002847 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002848 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002849 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002850 ETH_ALEN))
2851 break;
2852
Arend van Spriel40c8e952011-10-12 20:51:20 +02002853 if ((pmkid_len > 0)
2854 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002855 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002856 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002857 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002858 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2859 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002860 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002861 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2862 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002863 WLAN_PMKID_LEN);
2864 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002865 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002866 } else
2867 err = -EINVAL;
2868
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002869 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002870
Arend van Sprield96b8012012-12-05 15:26:02 +01002871 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002872 return err;
2873
2874}
2875
2876static s32
2877brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2878{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002879 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002880 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002881 s32 err = 0;
2882
Arend van Sprield96b8012012-12-05 15:26:02 +01002883 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002884 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002885 return -EIO;
2886
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002887 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2888 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002889
Arend van Sprield96b8012012-12-05 15:26:02 +01002890 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002891 return err;
2892
2893}
2894
Arend van Spriele5806072012-09-19 22:21:08 +02002895/*
2896 * PFN result doesn't have all the info which are
2897 * required by the supplicant
2898 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2899 * via wl_inform_single_bss in the required format. Escan does require the
2900 * scan request in the form of cfg80211_scan_request. For timebeing, create
2901 * cfg80211_scan_request one out of the received PNO event.
2902 */
2903static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002904brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002905 const struct brcmf_event_msg *e, void *data)
2906{
Arend van Spriel19937322012-11-05 16:22:32 -08002907 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriele5806072012-09-19 22:21:08 +02002908 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2909 struct cfg80211_scan_request *request = NULL;
2910 struct cfg80211_ssid *ssid = NULL;
2911 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002912 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002913 int err = 0;
2914 int channel_req = 0;
2915 int band = 0;
2916 struct brcmf_pno_scanresults_le *pfn_result;
2917 u32 result_count;
2918 u32 status;
2919
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002920 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002921
Arend van Spriel5c36b992012-11-14 18:46:05 -08002922 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002923 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002924 return 0;
2925 }
2926
2927 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2928 result_count = le32_to_cpu(pfn_result->count);
2929 status = le32_to_cpu(pfn_result->status);
2930
2931 /*
2932 * PFN event is limited to fit 512 bytes so we may get
2933 * multiple NET_FOUND events. For now place a warning here.
2934 */
2935 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002936 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002937 if (result_count > 0) {
2938 int i;
2939
2940 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002941 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2942 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002943 if (!request || !ssid || !channel) {
2944 err = -ENOMEM;
2945 goto out_err;
2946 }
2947
2948 request->wiphy = wiphy;
2949 data += sizeof(struct brcmf_pno_scanresults_le);
2950 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2951
2952 for (i = 0; i < result_count; i++) {
2953 netinfo = &netinfo_start[i];
2954 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002955 brcmf_err("Invalid netinfo ptr. index: %d\n",
2956 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002957 err = -EINVAL;
2958 goto out_err;
2959 }
2960
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002961 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2962 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002963 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2964 ssid[i].ssid_len = netinfo->SSID_len;
2965 request->n_ssids++;
2966
2967 channel_req = netinfo->channel;
2968 if (channel_req <= CH_MAX_2G_CHANNEL)
2969 band = NL80211_BAND_2GHZ;
2970 else
2971 band = NL80211_BAND_5GHZ;
2972 channel[i].center_freq =
2973 ieee80211_channel_to_frequency(channel_req,
2974 band);
2975 channel[i].band = band;
2976 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2977 request->channels[i] = &channel[i];
2978 request->n_channels++;
2979 }
2980
2981 /* assign parsed ssid array */
2982 if (request->n_ssids)
2983 request->ssids = &ssid[0];
2984
Arend van Sprielc1179032012-10-22 13:55:33 -07002985 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002986 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002987 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002988 }
2989
Arend van Sprielc1179032012-10-22 13:55:33 -07002990 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriela0f472a2013-04-05 10:57:49 +02002991 err = brcmf_do_escan(cfg, wiphy, ifp, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002992 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002993 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002994 goto out_err;
2995 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002996 cfg->sched_escan = true;
2997 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002998 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002999 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003000 goto out_err;
3001 }
3002
3003 kfree(ssid);
3004 kfree(channel);
3005 kfree(request);
3006 return 0;
3007
3008out_err:
3009 kfree(ssid);
3010 kfree(channel);
3011 kfree(request);
3012 cfg80211_sched_scan_stopped(wiphy);
3013 return err;
3014}
3015
Arend van Spriele5806072012-09-19 22:21:08 +02003016static int brcmf_dev_pno_clean(struct net_device *ndev)
3017{
Arend van Spriele5806072012-09-19 22:21:08 +02003018 int ret;
3019
3020 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003021 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003022 if (ret == 0) {
3023 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003024 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3025 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003026 }
3027 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003028 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003029
3030 return ret;
3031}
3032
3033static int brcmf_dev_pno_config(struct net_device *ndev)
3034{
3035 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003036
3037 memset(&pfn_param, 0, sizeof(pfn_param));
3038 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3039
3040 /* set extra pno params */
3041 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3042 pfn_param.repeat = BRCMF_PNO_REPEAT;
3043 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3044
3045 /* set up pno scan fr */
3046 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3047
Arend van Sprielac24be62012-10-22 10:36:23 -07003048 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3049 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003050}
3051
3052static int
3053brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3054 struct net_device *ndev,
3055 struct cfg80211_sched_scan_request *request)
3056{
Arend van Sprielc1179032012-10-22 13:55:33 -07003057 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003058 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003059 struct brcmf_pno_net_param_le pfn;
3060 int i;
3061 int ret = 0;
3062
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003063 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003064 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003065 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003066 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003067 return -EAGAIN;
3068 }
Arend van Spriel1687eee2013-04-23 12:53:11 +02003069 if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
3070 brcmf_err("Scanning suppressed: status (%lu)\n",
3071 cfg->scan_status);
3072 return -EAGAIN;
3073 }
Arend van Spriele5806072012-09-19 22:21:08 +02003074
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003075 if (!request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003076 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
Arend van Sprieldc7bdbf2013-03-03 12:45:25 +01003077 request->n_ssids);
Arend van Spriele5806072012-09-19 22:21:08 +02003078 return -EINVAL;
3079 }
3080
3081 if (request->n_ssids > 0) {
3082 for (i = 0; i < request->n_ssids; i++) {
3083 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003084 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3085 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003086
3087 /*
3088 * match_set ssids is a supert set of n_ssid list,
3089 * so we need not add these set seperately.
3090 */
3091 }
3092 }
3093
3094 if (request->n_match_sets > 0) {
3095 /* clean up everything */
3096 ret = brcmf_dev_pno_clean(ndev);
3097 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003098 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003099 return ret;
3100 }
3101
3102 /* configure pno */
3103 ret = brcmf_dev_pno_config(ndev);
3104 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003105 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003106 return -EINVAL;
3107 }
3108
3109 /* configure each match set */
3110 for (i = 0; i < request->n_match_sets; i++) {
3111 struct cfg80211_ssid *ssid;
3112 u32 ssid_len;
3113
3114 ssid = &request->match_sets[i].ssid;
3115 ssid_len = ssid->ssid_len;
3116
3117 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003118 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003119 continue;
3120 }
3121 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3122 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3123 pfn.wsec = cpu_to_le32(0);
3124 pfn.infra = cpu_to_le32(1);
3125 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3126 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3127 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003128 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003129 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003130 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3131 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003132 }
3133 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003134 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003135 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003136 return -EINVAL;
3137 }
3138 } else {
3139 return -EINVAL;
3140 }
3141
3142 return 0;
3143}
3144
3145static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3146 struct net_device *ndev)
3147{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003148 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003149
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003150 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003151 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003152 if (cfg->sched_escan)
Arend van Spriela0f472a2013-04-05 10:57:49 +02003153 brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003154 return 0;
3155}
Arend van Spriele5806072012-09-19 22:21:08 +02003156
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003157#ifdef CONFIG_NL80211_TESTMODE
David Spinadelfc73f112013-07-31 18:04:15 +03003158static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
3159 struct wireless_dev *wdev,
3160 void *data, int len)
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003161{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003162 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003163 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003164 struct brcmf_dcmd *dcmd = data;
3165 struct sk_buff *reply;
3166 int ret;
3167
Arend van Sprield96b8012012-12-05 15:26:02 +01003168 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3169 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003170
3171 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003172 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3173 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003174 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003175 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3176 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003177 if (ret == 0) {
3178 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3179 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3180 ret = cfg80211_testmode_reply(reply);
3181 }
3182 return ret;
3183}
3184#endif
3185
Hante Meuleman1f170112013-02-06 18:40:38 +01003186static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003187{
3188 s32 err;
3189
3190 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003191 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003192 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003193 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003194 return err;
3195 }
3196 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003197 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003198 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003199 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003200 return err;
3201 }
3202 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003203 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003204 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003205 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003206 return err;
3207 }
3208
3209 return 0;
3210}
3211
3212static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3213{
3214 if (is_rsn_ie)
3215 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3216
3217 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3218}
3219
3220static s32
3221brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003222 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003223{
Arend van Sprielac24be62012-10-22 10:36:23 -07003224 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003225 u32 auth = 0; /* d11 open authentication */
3226 u16 count;
3227 s32 err = 0;
3228 s32 len = 0;
3229 u32 i;
3230 u32 wsec;
3231 u32 pval = 0;
3232 u32 gval = 0;
3233 u32 wpa_auth = 0;
3234 u32 offset;
3235 u8 *data;
3236 u16 rsn_cap;
3237 u32 wme_bss_disable;
3238
Arend van Sprield96b8012012-12-05 15:26:02 +01003239 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003240 if (wpa_ie == NULL)
3241 goto exit;
3242
3243 len = wpa_ie->len + TLV_HDR_LEN;
3244 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003245 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003246 if (!is_rsn_ie)
3247 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003248 else
3249 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003250
3251 /* check for multicast cipher suite */
3252 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3253 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003254 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003255 goto exit;
3256 }
3257
3258 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3259 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003260 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003261 goto exit;
3262 }
3263 offset += TLV_OUI_LEN;
3264
3265 /* pick up multicast cipher */
3266 switch (data[offset]) {
3267 case WPA_CIPHER_NONE:
3268 gval = 0;
3269 break;
3270 case WPA_CIPHER_WEP_40:
3271 case WPA_CIPHER_WEP_104:
3272 gval = WEP_ENABLED;
3273 break;
3274 case WPA_CIPHER_TKIP:
3275 gval = TKIP_ENABLED;
3276 break;
3277 case WPA_CIPHER_AES_CCM:
3278 gval = AES_ENABLED;
3279 break;
3280 default:
3281 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003282 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003283 goto exit;
3284 }
3285
3286 offset++;
3287 /* walk thru unicast cipher list and pick up what we recognize */
3288 count = data[offset] + (data[offset + 1] << 8);
3289 offset += WPA_IE_SUITE_COUNT_LEN;
3290 /* Check for unicast suite(s) */
3291 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3292 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003293 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003294 goto exit;
3295 }
3296 for (i = 0; i < count; i++) {
3297 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3298 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003299 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003300 goto exit;
3301 }
3302 offset += TLV_OUI_LEN;
3303 switch (data[offset]) {
3304 case WPA_CIPHER_NONE:
3305 break;
3306 case WPA_CIPHER_WEP_40:
3307 case WPA_CIPHER_WEP_104:
3308 pval |= WEP_ENABLED;
3309 break;
3310 case WPA_CIPHER_TKIP:
3311 pval |= TKIP_ENABLED;
3312 break;
3313 case WPA_CIPHER_AES_CCM:
3314 pval |= AES_ENABLED;
3315 break;
3316 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003317 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003318 }
3319 offset++;
3320 }
3321 /* walk thru auth management suite list and pick up what we recognize */
3322 count = data[offset] + (data[offset + 1] << 8);
3323 offset += WPA_IE_SUITE_COUNT_LEN;
3324 /* Check for auth key management suite(s) */
3325 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3326 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003327 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003328 goto exit;
3329 }
3330 for (i = 0; i < count; i++) {
3331 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3332 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003333 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003334 goto exit;
3335 }
3336 offset += TLV_OUI_LEN;
3337 switch (data[offset]) {
3338 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003339 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003340 wpa_auth |= WPA_AUTH_NONE;
3341 break;
3342 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003343 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003344 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3345 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3346 break;
3347 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003348 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003349 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3350 (wpa_auth |= WPA_AUTH_PSK);
3351 break;
3352 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003353 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003354 }
3355 offset++;
3356 }
3357
3358 if (is_rsn_ie) {
3359 wme_bss_disable = 1;
3360 if ((offset + RSN_CAP_LEN) <= len) {
3361 rsn_cap = data[offset] + (data[offset + 1] << 8);
3362 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3363 wme_bss_disable = 0;
3364 }
3365 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003366 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003367 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003368 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003369 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003370 goto exit;
3371 }
3372 }
3373 /* FOR WPS , set SES_OW_ENABLED */
3374 wsec = (pval | gval | SES_OW_ENABLED);
3375
3376 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003377 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003378 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003379 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003380 goto exit;
3381 }
3382 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003383 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003384 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003385 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003386 goto exit;
3387 }
3388 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003389 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003390 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003391 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003392 goto exit;
3393 }
3394
3395exit:
3396 return err;
3397}
3398
3399static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003400brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003401 struct parsed_vndr_ies *vndr_ies)
3402{
3403 s32 err = 0;
3404 struct brcmf_vs_tlv *vndrie;
3405 struct brcmf_tlv *ie;
3406 struct parsed_vndr_ie_info *parsed_info;
3407 s32 remaining_len;
3408
3409 remaining_len = (s32)vndr_ie_len;
3410 memset(vndr_ies, 0, sizeof(*vndr_ies));
3411
3412 ie = (struct brcmf_tlv *)vndr_ie_buf;
3413 while (ie) {
3414 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3415 goto next;
3416 vndrie = (struct brcmf_vs_tlv *)ie;
3417 /* len should be bigger than OUI length + one */
3418 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003419 brcmf_err("invalid vndr ie. length is too small %d\n",
3420 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003421 goto next;
3422 }
3423 /* if wpa or wme ie, do not add ie */
3424 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3425 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3426 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003427 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003428 goto next;
3429 }
3430
3431 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3432
3433 /* save vndr ie information */
3434 parsed_info->ie_ptr = (char *)vndrie;
3435 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3436 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3437
3438 vndr_ies->count++;
3439
Arend van Sprield96b8012012-12-05 15:26:02 +01003440 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3441 parsed_info->vndrie.oui[0],
3442 parsed_info->vndrie.oui[1],
3443 parsed_info->vndrie.oui[2],
3444 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003445
Arend van Spriel9f440b72013-02-08 15:53:36 +01003446 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003447 break;
3448next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003449 remaining_len -= (ie->len + TLV_HDR_LEN);
3450 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003451 ie = NULL;
3452 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003453 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3454 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003455 }
3456 return err;
3457}
3458
3459static u32
3460brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3461{
3462
3463 __le32 iecount_le;
3464 __le32 pktflag_le;
3465
3466 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3467 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3468
3469 iecount_le = cpu_to_le32(1);
3470 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3471
3472 pktflag_le = cpu_to_le32(pktflag);
3473 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3474
3475 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3476
3477 return ie_len + VNDR_IE_HDR_SIZE;
3478}
3479
Arend van Spriel1332e262012-11-05 16:22:18 -08003480s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3481 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003482{
Arend van Spriel1332e262012-11-05 16:22:18 -08003483 struct brcmf_if *ifp;
3484 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003485 s32 err = 0;
3486 u8 *iovar_ie_buf;
3487 u8 *curr_ie_buf;
3488 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003489 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003490 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003491 u32 del_add_ie_buf_len = 0;
3492 u32 total_ie_buf_len = 0;
3493 u32 parsed_ie_buf_len = 0;
3494 struct parsed_vndr_ies old_vndr_ies;
3495 struct parsed_vndr_ies new_vndr_ies;
3496 struct parsed_vndr_ie_info *vndrie_info;
3497 s32 i;
3498 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003499 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003500
Arend van Spriel1332e262012-11-05 16:22:18 -08003501 if (!vif)
3502 return -ENODEV;
3503 ifp = vif->ifp;
3504 saved_ie = &vif->saved_ie;
3505
Arend van Sprield96b8012012-12-05 15:26:02 +01003506 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003507 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3508 if (!iovar_ie_buf)
3509 return -ENOMEM;
3510 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003511 switch (pktflag) {
3512 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3513 mgmt_ie_buf = saved_ie->probe_req_ie;
3514 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3515 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3516 break;
3517 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3518 mgmt_ie_buf = saved_ie->probe_res_ie;
3519 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3520 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3521 break;
3522 case BRCMF_VNDR_IE_BEACON_FLAG:
3523 mgmt_ie_buf = saved_ie->beacon_ie;
3524 mgmt_ie_len = &saved_ie->beacon_ie_len;
3525 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3526 break;
3527 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3528 mgmt_ie_buf = saved_ie->assoc_req_ie;
3529 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3530 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3531 break;
3532 default:
3533 err = -EPERM;
3534 brcmf_err("not suitable type\n");
3535 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003536 }
3537
3538 if (vndr_ie_len > mgmt_ie_buf_len) {
3539 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003540 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003541 goto exit;
3542 }
3543
3544 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3545 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3546 ptr = curr_ie_buf;
3547 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3548 for (i = 0; i < new_vndr_ies.count; i++) {
3549 vndrie_info = &new_vndr_ies.ie_info[i];
3550 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3551 vndrie_info->ie_len);
3552 parsed_ie_buf_len += vndrie_info->ie_len;
3553 }
3554 }
3555
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003556 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003557 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3558 (memcmp(mgmt_ie_buf, curr_ie_buf,
3559 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003560 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003561 goto exit;
3562 }
3563
3564 /* parse old vndr_ie */
3565 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3566
3567 /* make a command to delete old ie */
3568 for (i = 0; i < old_vndr_ies.count; i++) {
3569 vndrie_info = &old_vndr_ies.ie_info[i];
3570
Arend van Sprield96b8012012-12-05 15:26:02 +01003571 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3572 vndrie_info->vndrie.id,
3573 vndrie_info->vndrie.len,
3574 vndrie_info->vndrie.oui[0],
3575 vndrie_info->vndrie.oui[1],
3576 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003577
3578 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3579 vndrie_info->ie_ptr,
3580 vndrie_info->ie_len,
3581 "del");
3582 curr_ie_buf += del_add_ie_buf_len;
3583 total_ie_buf_len += del_add_ie_buf_len;
3584 }
3585 }
3586
3587 *mgmt_ie_len = 0;
3588 /* Add if there is any extra IE */
3589 if (mgmt_ie_buf && parsed_ie_buf_len) {
3590 ptr = mgmt_ie_buf;
3591
3592 remained_buf_len = mgmt_ie_buf_len;
3593
3594 /* make a command to add new ie */
3595 for (i = 0; i < new_vndr_ies.count; i++) {
3596 vndrie_info = &new_vndr_ies.ie_info[i];
3597
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003598 /* verify remained buf size before copy data */
3599 if (remained_buf_len < (vndrie_info->vndrie.len +
3600 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003601 brcmf_err("no space in mgmt_ie_buf: len left %d",
3602 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003603 break;
3604 }
3605 remained_buf_len -= (vndrie_info->ie_len +
3606 VNDR_IE_VSIE_OFFSET);
3607
Arend van Sprield96b8012012-12-05 15:26:02 +01003608 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3609 vndrie_info->vndrie.id,
3610 vndrie_info->vndrie.len,
3611 vndrie_info->vndrie.oui[0],
3612 vndrie_info->vndrie.oui[1],
3613 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003614
3615 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3616 vndrie_info->ie_ptr,
3617 vndrie_info->ie_len,
3618 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003619
3620 /* save the parsed IE in wl struct */
3621 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3622 vndrie_info->ie_len);
3623 *mgmt_ie_len += vndrie_info->ie_len;
3624
3625 curr_ie_buf += del_add_ie_buf_len;
3626 total_ie_buf_len += del_add_ie_buf_len;
3627 }
3628 }
3629 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003630 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003631 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003632 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003633 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003634 }
3635
3636exit:
3637 kfree(iovar_ie_buf);
3638 return err;
3639}
3640
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003641s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3642{
3643 s32 pktflags[] = {
3644 BRCMF_VNDR_IE_PRBREQ_FLAG,
3645 BRCMF_VNDR_IE_PRBRSP_FLAG,
3646 BRCMF_VNDR_IE_BEACON_FLAG
3647 };
3648 int i;
3649
3650 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3651 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3652
3653 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3654 return 0;
3655}
3656
Hante Meuleman1a873342012-09-27 14:17:54 +02003657static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01003658brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3659 struct cfg80211_beacon_data *beacon)
3660{
3661 s32 err;
3662
3663 /* Set Beacon IEs to FW */
3664 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3665 beacon->tail, beacon->tail_len);
3666 if (err) {
3667 brcmf_err("Set Beacon IE Failed\n");
3668 return err;
3669 }
3670 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3671
3672 /* Set Probe Response IEs to FW */
3673 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3674 beacon->proberesp_ies,
3675 beacon->proberesp_ies_len);
3676 if (err)
3677 brcmf_err("Set Probe Resp IE Failed\n");
3678 else
3679 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3680
3681 return err;
3682}
3683
3684static s32
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003685brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
3686 struct brcmf_if *ifp,
3687 struct ieee80211_channel *channel)
3688{
3689 u16 chanspec;
3690 s32 err;
3691
3692 brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
3693 channel->center_freq);
3694
3695 chanspec = channel_to_chanspec(&cfg->d11inf, channel);
3696 err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3697
3698 return err;
3699}
3700
3701static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02003702brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3703 struct cfg80211_ap_settings *settings)
3704{
3705 s32 ie_offset;
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003706 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielac24be62012-10-22 10:36:23 -07003707 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003708 struct brcmf_tlv *ssid_ie;
3709 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003710 s32 err = -EPERM;
3711 struct brcmf_tlv *rsn_ie;
3712 struct brcmf_vs_tlv *wpa_ie;
3713 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01003714 enum nl80211_iftype dev_role;
3715 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003716
Arend van Sprield96b8012012-12-05 15:26:02 +01003717 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3718 cfg80211_get_chandef_type(&settings->chandef),
3719 settings->beacon_interval,
3720 settings->dtim_period);
3721 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3722 settings->ssid, settings->ssid_len, settings->auth_type,
3723 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003724
Hante Meuleman426d0a52013-02-08 15:53:53 +01003725 dev_role = ifp->vif->wdev.iftype;
Hante Meuleman1a873342012-09-27 14:17:54 +02003726
3727 memset(&ssid_le, 0, sizeof(ssid_le));
3728 if (settings->ssid == NULL || settings->ssid_len == 0) {
3729 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3730 ssid_ie = brcmf_parse_tlvs(
3731 (u8 *)&settings->beacon.head[ie_offset],
3732 settings->beacon.head_len - ie_offset,
3733 WLAN_EID_SSID);
3734 if (!ssid_ie)
3735 return -EINVAL;
3736
3737 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3738 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003739 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003740 } else {
3741 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3742 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3743 }
3744
Arend van Sprielf96aa072013-04-05 10:57:48 +02003745 brcmf_set_mpc(ifp, 0);
Hante Meulemanb3657452013-05-27 21:09:53 +02003746 brcmf_configure_arp_offload(ifp, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003747
3748 /* find the RSN_IE */
3749 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3750 settings->beacon.tail_len, WLAN_EID_RSN);
3751
3752 /* find the WPA_IE */
3753 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3754 settings->beacon.tail_len);
3755
Hante Meuleman1a873342012-09-27 14:17:54 +02003756 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003757 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003758 if (wpa_ie != NULL) {
3759 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003760 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003761 if (err < 0)
3762 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003763 } else {
3764 /* RSN IE */
3765 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003766 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003767 if (err < 0)
3768 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003769 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003770 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003771 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003772 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003773 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003774
Hante Meulemana0f07952013-02-08 15:53:47 +01003775 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02003776
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02003777 err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
3778 if (err < 0) {
3779 brcmf_err("Set Channel failed, %d\n", err);
3780 goto exit;
3781 }
3782
Hante Meuleman1a873342012-09-27 14:17:54 +02003783 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003784 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003785 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003786 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003787 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003788 goto exit;
3789 }
3790 }
3791 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003792 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003793 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003794 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003795 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003796 goto exit;
3797 }
3798 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003799
3800 if (dev_role == NL80211_IFTYPE_AP) {
3801 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3802 if (err < 0) {
3803 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3804 goto exit;
3805 }
Hante Meuleman2880b862013-02-08 12:06:31 +01003806 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003807 }
3808
Hante Meulemana0f07952013-02-08 15:53:47 +01003809 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003810 if (err < 0) {
Hante Meulemana0f07952013-02-08 15:53:47 +01003811 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003812 goto exit;
3813 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003814 if (dev_role == NL80211_IFTYPE_AP) {
3815 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3816 if (err < 0) {
3817 brcmf_err("setting AP mode failed %d\n", err);
3818 goto exit;
3819 }
3820 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3821 if (err < 0) {
3822 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3823 goto exit;
3824 }
3825
3826 memset(&join_params, 0, sizeof(join_params));
3827 /* join parameters starts with ssid */
3828 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3829 /* create softap */
3830 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3831 &join_params, sizeof(join_params));
3832 if (err < 0) {
3833 brcmf_err("SET SSID error (%d)\n", err);
3834 goto exit;
3835 }
3836 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3837 } else {
3838 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3839 sizeof(ssid_le));
3840 if (err < 0) {
3841 brcmf_err("setting ssid failed %d\n", err);
3842 goto exit;
3843 }
3844 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3845 bss_enable.enable = cpu_to_le32(1);
3846 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3847 sizeof(bss_enable));
3848 if (err < 0) {
3849 brcmf_err("bss_enable config failed %d\n", err);
3850 goto exit;
3851 }
3852
3853 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3854 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003855 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3856 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003857
3858exit:
Hante Meulemanb3657452013-05-27 21:09:53 +02003859 if (err) {
Arend van Sprielf96aa072013-04-05 10:57:48 +02003860 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003861 brcmf_configure_arp_offload(ifp, true);
3862 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003863 return err;
3864}
3865
3866static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3867{
Arend van Sprielc1179032012-10-22 13:55:33 -07003868 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003869 s32 err;
Hante Meuleman426d0a52013-02-08 15:53:53 +01003870 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman5c33a942013-04-02 21:06:18 +02003871 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003872
Arend van Sprield96b8012012-12-05 15:26:02 +01003873 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003874
Hante Meuleman426d0a52013-02-08 15:53:53 +01003875 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003876 /* Due to most likely deauths outstanding we sleep */
3877 /* first to make sure they get processed by fw. */
3878 msleep(400);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003879
3880 memset(&join_params, 0, sizeof(join_params));
3881 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3882 &join_params, sizeof(join_params));
3883 if (err < 0)
3884 brcmf_err("SET SSID error (%d)\n", err);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003885 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003886 if (err < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003887 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman5c33a942013-04-02 21:06:18 +02003888 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
3889 if (err < 0)
3890 brcmf_err("setting AP mode failed %d\n", err);
3891 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
3892 if (err < 0)
3893 brcmf_err("setting INFRA mode failed %d\n", err);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003894 } else {
3895 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3896 bss_enable.enable = cpu_to_le32(0);
3897 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3898 sizeof(bss_enable));
3899 if (err < 0)
3900 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003901 }
Arend van Sprielf96aa072013-04-05 10:57:48 +02003902 brcmf_set_mpc(ifp, 1);
Hante Meulemanb3657452013-05-27 21:09:53 +02003903 brcmf_configure_arp_offload(ifp, true);
Hante Meuleman426d0a52013-02-08 15:53:53 +01003904 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3905 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3906
Hante Meuleman1a873342012-09-27 14:17:54 +02003907 return err;
3908}
3909
Hante Meulemana0f07952013-02-08 15:53:47 +01003910static s32
3911brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3912 struct cfg80211_beacon_data *info)
3913{
Hante Meulemana0f07952013-02-08 15:53:47 +01003914 struct brcmf_if *ifp = netdev_priv(ndev);
3915 s32 err;
3916
3917 brcmf_dbg(TRACE, "Enter\n");
3918
Hante Meulemana0f07952013-02-08 15:53:47 +01003919 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3920
3921 return err;
3922}
3923
Hante Meuleman1a873342012-09-27 14:17:54 +02003924static int
3925brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3926 u8 *mac)
3927{
Hante Meulemana0f07952013-02-08 15:53:47 +01003928 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003929 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003930 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003931 s32 err;
3932
3933 if (!mac)
3934 return -EFAULT;
3935
Arend van Sprield96b8012012-12-05 15:26:02 +01003936 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003937
Hante Meulemana0f07952013-02-08 15:53:47 +01003938 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3939 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07003940 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003941 return -EIO;
3942
3943 memcpy(&scbval.ea, mac, ETH_ALEN);
3944 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003945 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003946 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003947 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003948 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01003949
Arend van Sprield96b8012012-12-05 15:26:02 +01003950 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003951 return err;
3952}
3953
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003954
3955static void
3956brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3957 struct wireless_dev *wdev,
3958 u16 frame_type, bool reg)
3959{
Arend van Spriel7fa2e352013-04-05 10:57:47 +02003960 struct brcmf_cfg80211_vif *vif;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003961 u16 mgmt_type;
3962
3963 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3964
3965 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
Arend van Spriel7fa2e352013-04-05 10:57:47 +02003966 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003967 if (reg)
3968 vif->mgmt_rx_reg |= BIT(mgmt_type);
3969 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01003970 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003971}
3972
3973
3974static int
3975brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003976 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003977{
3978 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02003979 struct ieee80211_channel *chan = params->chan;
3980 const u8 *buf = params->buf;
3981 size_t len = params->len;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003982 const struct ieee80211_mgmt *mgmt;
3983 struct brcmf_cfg80211_vif *vif;
3984 s32 err = 0;
3985 s32 ie_offset;
3986 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01003987 struct brcmf_fil_action_frame_le *action_frame;
3988 struct brcmf_fil_af_params_le *af_params;
3989 bool ack;
3990 s32 chan_nr;
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02003991 u32 freq;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003992
3993 brcmf_dbg(TRACE, "Enter\n");
3994
3995 *cookie = 0;
3996
3997 mgmt = (const struct ieee80211_mgmt *)buf;
3998
Hante Meulemana0f07952013-02-08 15:53:47 +01003999 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
4000 brcmf_err("Driver only allows MGMT packet type\n");
4001 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004002 }
Hante Meulemana0f07952013-02-08 15:53:47 +01004003
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004004 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4005
Hante Meulemana0f07952013-02-08 15:53:47 +01004006 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4007 /* Right now the only reason to get a probe response */
4008 /* is for p2p listen response or for p2p GO from */
4009 /* wpa_supplicant. Unfortunately the probe is send */
4010 /* on primary ndev, while dongle wants it on the p2p */
4011 /* vif. Since this is only reason for a probe */
4012 /* response to be sent, the vif is taken from cfg. */
4013 /* If ever desired to send proberesp for non p2p */
4014 /* response then data should be checked for */
4015 /* "DIRECT-". Note in future supplicant will take */
4016 /* dedicated p2p wdev to do this and then this 'hack'*/
4017 /* is not needed anymore. */
4018 ie_offset = DOT11_MGMT_HDR_LEN +
4019 DOT11_BCN_PRB_FIXED_LEN;
4020 ie_len = len - ie_offset;
Hante Meulemana0f07952013-02-08 15:53:47 +01004021 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4022 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4023 err = brcmf_vif_set_mgmt_ie(vif,
4024 BRCMF_VNDR_IE_PRBRSP_FLAG,
4025 &buf[ie_offset],
4026 ie_len);
4027 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
4028 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004029 } else if (ieee80211_is_action(mgmt->frame_control)) {
4030 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
4031 if (af_params == NULL) {
4032 brcmf_err("unable to allocate frame\n");
4033 err = -ENOMEM;
4034 goto exit;
4035 }
4036 action_frame = &af_params->action_frame;
4037 /* Add the packet Id */
4038 action_frame->packet_id = cpu_to_le32(*cookie);
4039 /* Add BSSID */
4040 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
4041 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
4042 /* Add the length exepted for 802.11 header */
4043 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
Antonio Quartullic2ff8ca2013-06-11 14:20:01 +02004044 /* Add the channel. Use the one specified as parameter if any or
4045 * the current one (got from the firmware) otherwise
4046 */
4047 if (chan)
4048 freq = chan->center_freq;
4049 else
4050 brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
4051 &freq);
4052 chan_nr = ieee80211_frequency_to_channel(freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004053 af_params->channel = cpu_to_le32(chan_nr);
4054
4055 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4056 le16_to_cpu(action_frame->len));
4057
4058 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
Antonio Quartulli86a9c4a2013-06-19 13:35:31 +02004059 *cookie, le16_to_cpu(action_frame->len), freq);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004060
Arend van Spriel7fa2e352013-04-05 10:57:47 +02004061 ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
Hante Meuleman18e2f612013-02-08 15:53:49 +01004062 af_params);
4063
4064 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4065 GFP_KERNEL);
4066 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004067 } else {
4068 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4069 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4070 }
4071
Hante Meuleman18e2f612013-02-08 15:53:49 +01004072exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004073 return err;
4074}
4075
4076
4077static int
4078brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4079 struct wireless_dev *wdev,
4080 u64 cookie)
4081{
4082 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4083 struct brcmf_cfg80211_vif *vif;
4084 int err = 0;
4085
4086 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4087
4088 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4089 if (vif == NULL) {
4090 brcmf_err("No p2p device available for probe response\n");
4091 err = -ENODEV;
4092 goto exit;
4093 }
4094 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4095exit:
4096 return err;
4097}
4098
Piotr Haber61730d42013-04-23 12:53:12 +02004099static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
4100 struct wireless_dev *wdev,
4101 enum nl80211_crit_proto_id proto,
4102 u16 duration)
4103{
4104 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4105 struct brcmf_cfg80211_vif *vif;
4106
4107 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4108
4109 /* only DHCP support for now */
4110 if (proto != NL80211_CRIT_PROTO_DHCP)
4111 return -EINVAL;
4112
4113 /* suppress and abort scanning */
4114 set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4115 brcmf_abort_scanning(cfg);
4116
4117 return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
4118}
4119
4120static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
4121 struct wireless_dev *wdev)
4122{
4123 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4124 struct brcmf_cfg80211_vif *vif;
4125
4126 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
4127
4128 brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
4129 clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
4130}
4131
Arend van Spriel89c2f382013-08-10 12:27:25 +02004132static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
4133{
4134 int ret;
4135
4136 switch (oper) {
4137 case NL80211_TDLS_DISCOVERY_REQ:
4138 ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
4139 break;
4140 case NL80211_TDLS_SETUP:
4141 ret = BRCMF_TDLS_MANUAL_EP_CREATE;
4142 break;
4143 case NL80211_TDLS_TEARDOWN:
4144 ret = BRCMF_TDLS_MANUAL_EP_DELETE;
4145 break;
4146 default:
4147 brcmf_err("unsupported operation: %d\n", oper);
4148 ret = -EOPNOTSUPP;
4149 }
4150 return ret;
4151}
4152
4153static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
4154 struct net_device *ndev, u8 *peer,
4155 enum nl80211_tdls_operation oper)
4156{
4157 struct brcmf_if *ifp;
4158 struct brcmf_tdls_iovar_le info;
4159 int ret = 0;
4160
4161 ret = brcmf_convert_nl80211_tdls_oper(oper);
4162 if (ret < 0)
4163 return ret;
4164
4165 ifp = netdev_priv(ndev);
4166 memset(&info, 0, sizeof(info));
4167 info.mode = (u8)ret;
4168 if (peer)
4169 memcpy(info.ea, peer, ETH_ALEN);
4170
4171 ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
4172 &info, sizeof(info));
4173 if (ret < 0)
4174 brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
4175
4176 return ret;
4177}
4178
Arend van Spriel5b435de2011-10-05 13:19:03 +02004179static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004180 .add_virtual_intf = brcmf_cfg80211_add_iface,
4181 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004182 .change_virtual_intf = brcmf_cfg80211_change_iface,
4183 .scan = brcmf_cfg80211_scan,
4184 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4185 .join_ibss = brcmf_cfg80211_join_ibss,
4186 .leave_ibss = brcmf_cfg80211_leave_ibss,
4187 .get_station = brcmf_cfg80211_get_station,
4188 .set_tx_power = brcmf_cfg80211_set_tx_power,
4189 .get_tx_power = brcmf_cfg80211_get_tx_power,
4190 .add_key = brcmf_cfg80211_add_key,
4191 .del_key = brcmf_cfg80211_del_key,
4192 .get_key = brcmf_cfg80211_get_key,
4193 .set_default_key = brcmf_cfg80211_config_default_key,
4194 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4195 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004196 .connect = brcmf_cfg80211_connect,
4197 .disconnect = brcmf_cfg80211_disconnect,
4198 .suspend = brcmf_cfg80211_suspend,
4199 .resume = brcmf_cfg80211_resume,
4200 .set_pmksa = brcmf_cfg80211_set_pmksa,
4201 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004202 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004203 .start_ap = brcmf_cfg80211_start_ap,
4204 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004205 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004206 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004207 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4208 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004209 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4210 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4211 .remain_on_channel = brcmf_p2p_remain_on_channel,
4212 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Spriel27f10e32013-04-05 10:57:50 +02004213 .start_p2p_device = brcmf_p2p_start_device,
4214 .stop_p2p_device = brcmf_p2p_stop_device,
Piotr Haber61730d42013-04-23 12:53:12 +02004215 .crit_proto_start = brcmf_cfg80211_crit_proto_start,
4216 .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
Arend van Spriel89c2f382013-08-10 12:27:25 +02004217 .tdls_oper = brcmf_cfg80211_tdls_oper,
Johannes Berge3335472013-08-06 11:13:19 +02004218 CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004219};
4220
Arend van Spriel9f440b72013-02-08 15:53:36 +01004221static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004222{
Arend van Spriel9f440b72013-02-08 15:53:36 +01004223 switch (type) {
4224 case NL80211_IFTYPE_AP_VLAN:
4225 case NL80211_IFTYPE_WDS:
4226 case NL80211_IFTYPE_MONITOR:
4227 case NL80211_IFTYPE_MESH_POINT:
4228 return -ENOTSUPP;
4229 case NL80211_IFTYPE_ADHOC:
4230 return WL_MODE_IBSS;
4231 case NL80211_IFTYPE_STATION:
4232 case NL80211_IFTYPE_P2P_CLIENT:
4233 return WL_MODE_BSS;
4234 case NL80211_IFTYPE_AP:
4235 case NL80211_IFTYPE_P2P_GO:
4236 return WL_MODE_AP;
4237 case NL80211_IFTYPE_P2P_DEVICE:
4238 return WL_MODE_P2P;
4239 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004240 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01004241 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004242 }
4243
Arend van Spriel9f440b72013-02-08 15:53:36 +01004244 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004245}
4246
Arend van Spriele5806072012-09-19 22:21:08 +02004247static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4248{
Arend van Spriele5806072012-09-19 22:21:08 +02004249 /* scheduled scan settings */
4250 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4251 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4252 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4253 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02004254}
4255
Arend van Spriel9f440b72013-02-08 15:53:36 +01004256static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4257 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004258 .max = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004259 .types = BIT(NL80211_IFTYPE_STATION) |
4260 BIT(NL80211_IFTYPE_ADHOC) |
4261 BIT(NL80211_IFTYPE_AP)
4262 },
4263 {
4264 .max = 1,
4265 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4266 BIT(NL80211_IFTYPE_P2P_GO)
4267 },
Arend van Spriel9af221b2013-05-14 20:52:36 +02004268 {
4269 .max = 1,
4270 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4271 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004272};
4273static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4274 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004275 .max_interfaces = BRCMF_IFACE_MAX_CNT,
Hante Meuleman1c9d30c2013-05-27 21:09:58 +02004276 .num_different_channels = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004277 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4278 .limits = brcmf_iface_limits
4279 }
4280};
4281
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004282static const struct ieee80211_txrx_stypes
4283brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4284 [NL80211_IFTYPE_STATION] = {
4285 .tx = 0xffff,
4286 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4287 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4288 },
4289 [NL80211_IFTYPE_P2P_CLIENT] = {
4290 .tx = 0xffff,
4291 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4292 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4293 },
4294 [NL80211_IFTYPE_P2P_GO] = {
4295 .tx = 0xffff,
4296 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4297 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4298 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4299 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4300 BIT(IEEE80211_STYPE_AUTH >> 4) |
4301 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4302 BIT(IEEE80211_STYPE_ACTION >> 4)
Arend van Sprielbffc61c2013-04-05 10:57:52 +02004303 },
4304 [NL80211_IFTYPE_P2P_DEVICE] = {
4305 .tx = 0xffff,
4306 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4307 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004308 }
4309};
4310
Arend van Spriel3eacf862012-10-22 13:55:30 -07004311static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004312{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004313 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004314 s32 err = 0;
4315
Arend van Spriel3eacf862012-10-22 13:55:30 -07004316 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4317 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004318 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004319 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004320 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004321 set_wiphy_dev(wiphy, phydev);
4322 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004323 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004324 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4325 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4326 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01004327 BIT(NL80211_IFTYPE_AP) |
4328 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Arend van Spriel9af221b2013-05-14 20:52:36 +02004329 BIT(NL80211_IFTYPE_P2P_GO) |
4330 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel9f440b72013-02-08 15:53:36 +01004331 wiphy->iface_combinations = brcmf_iface_combos;
4332 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004333 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004334 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4335 wiphy->cipher_suites = __wl_cipher_suites;
4336 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004337 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004338 WIPHY_FLAG_OFFCHAN_TX |
Arend van Spriel89c2f382013-08-10 12:27:25 +02004339 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
4340 WIPHY_FLAG_SUPPORTS_TDLS;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004341 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4342 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004343 brcmf_wiphy_pno_params(wiphy);
Hante Meulemand48200b2013-04-03 12:40:29 +02004344 brcmf_dbg(INFO, "Registering custom regulatory\n");
Luis R. Rodrigueza2f73b62013-11-11 22:15:29 +01004345 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
Hante Meulemand48200b2013-04-03 12:40:29 +02004346 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004347 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004348 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004349 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004350 wiphy_free(wiphy);
4351 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004352 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004353 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004354}
4355
Arend van Spriel3eacf862012-10-22 13:55:30 -07004356struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004357 enum nl80211_iftype type,
4358 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004359{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004360 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004361
Arend van Spriel3eacf862012-10-22 13:55:30 -07004362 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4363 return ERR_PTR(-ENOSPC);
4364
Arend van Spriel33a6b152013-02-08 15:53:39 +01004365 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004366 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004367 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4368 if (!vif)
4369 return ERR_PTR(-ENOMEM);
4370
4371 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004372 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004373
Arend van Spriel9f440b72013-02-08 15:53:36 +01004374 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004375 vif->pm_block = pm_block;
4376 vif->roam_off = -1;
4377
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004378 brcmf_init_prof(&vif->profile);
4379
Arend van Spriel3eacf862012-10-22 13:55:30 -07004380 list_add_tail(&vif->list, &cfg->vif_list);
4381 cfg->vif_cnt++;
4382 return vif;
4383}
4384
Arend van Spriel24e28be2013-05-27 21:09:55 +02004385void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
4386 struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004387{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004388 list_del(&vif->list);
4389 cfg->vif_cnt--;
4390
4391 kfree(vif);
4392 if (!cfg->vif_cnt) {
Arend van Spriel24e28be2013-05-27 21:09:55 +02004393 wiphy_unregister(cfg->wiphy);
4394 wiphy_free(cfg->wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004395 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004396}
4397
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004398static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004399{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004400 u32 event = e->event_code;
4401 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004402
4403 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004404 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004405 return true;
4406 }
4407
4408 return false;
4409}
4410
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004411static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004412{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004413 u32 event = e->event_code;
4414 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004415
4416 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004417 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004418 return true;
4419 }
4420 return false;
4421}
4422
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004423static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004424 const struct brcmf_event_msg *e)
4425{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004426 u32 event = e->event_code;
4427 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004428
4429 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004430 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4431 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004432 return true;
4433 }
4434
4435 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004436 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004437 return true;
4438 }
4439
4440 return false;
4441}
4442
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004443static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004444{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004445 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004446
4447 kfree(conn_info->req_ie);
4448 conn_info->req_ie = NULL;
4449 conn_info->req_ie_len = 0;
4450 kfree(conn_info->resp_ie);
4451 conn_info->resp_ie = NULL;
4452 conn_info->resp_ie_len = 0;
4453}
4454
Hante Meuleman89286dc2013-02-08 15:53:46 +01004455static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4456 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004457{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004458 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004459 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004460 u32 req_len;
4461 u32 resp_len;
4462 s32 err = 0;
4463
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004464 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004465
Arend van Sprielac24be62012-10-22 10:36:23 -07004466 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4467 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004468 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004469 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004470 return err;
4471 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004472 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004473 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004474 req_len = le32_to_cpu(assoc_info->req_len);
4475 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004476 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004477 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004478 cfg->extra_buf,
4479 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004480 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004481 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004482 return err;
4483 }
4484 conn_info->req_ie_len = req_len;
4485 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004486 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004487 GFP_KERNEL);
4488 } else {
4489 conn_info->req_ie_len = 0;
4490 conn_info->req_ie = NULL;
4491 }
4492 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004493 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004494 cfg->extra_buf,
4495 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004496 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004497 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004498 return err;
4499 }
4500 conn_info->resp_ie_len = resp_len;
4501 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004502 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004503 GFP_KERNEL);
4504 } else {
4505 conn_info->resp_ie_len = 0;
4506 conn_info->resp_ie = NULL;
4507 }
Arend van Spriel16886732012-12-05 15:26:04 +01004508 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4509 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004510
4511 return err;
4512}
4513
4514static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004515brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004516 struct net_device *ndev,
4517 const struct brcmf_event_msg *e)
4518{
Arend van Sprielc1179032012-10-22 13:55:33 -07004519 struct brcmf_if *ifp = netdev_priv(ndev);
4520 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004521 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4522 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004523 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004524 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004525 struct brcmf_bss_info_le *bi;
Franky Lin83cf17a2013-04-11 13:28:50 +02004526 struct brcmu_chan ch;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004527 u32 freq;
4528 s32 err = 0;
Franky Lina180b832012-10-10 11:13:09 -07004529 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004530
Arend van Sprield96b8012012-12-05 15:26:02 +01004531 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004532
Hante Meuleman89286dc2013-02-08 15:53:46 +01004533 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004534 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004535 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004536
Franky Lina180b832012-10-10 11:13:09 -07004537 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4538 if (buf == NULL) {
4539 err = -ENOMEM;
4540 goto done;
4541 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004542
Franky Lina180b832012-10-10 11:13:09 -07004543 /* data sent to dongle has to be little endian */
4544 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004545 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004546 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004547
4548 if (err)
4549 goto done;
4550
4551 bi = (struct brcmf_bss_info_le *)(buf + 4);
Franky Lin83cf17a2013-04-11 13:28:50 +02004552 ch.chspec = le16_to_cpu(bi->chanspec);
4553 cfg->d11inf.decchspec(&ch);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004554
Franky Lin83cf17a2013-04-11 13:28:50 +02004555 if (ch.band == BRCMU_CHAN_BAND_2G)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004556 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4557 else
4558 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4559
Franky Lin83cf17a2013-04-11 13:28:50 +02004560 freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004561 notify_channel = ieee80211_get_channel(wiphy, freq);
4562
Franky Lina180b832012-10-10 11:13:09 -07004563done:
4564 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004565 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004566 conn_info->req_ie, conn_info->req_ie_len,
4567 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004568 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004569
Arend van Sprielc1179032012-10-22 13:55:33 -07004570 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004571 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004572 return err;
4573}
4574
4575static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004576brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004577 struct net_device *ndev, const struct brcmf_event_msg *e,
4578 bool completed)
4579{
Arend van Sprielc1179032012-10-22 13:55:33 -07004580 struct brcmf_if *ifp = netdev_priv(ndev);
4581 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004582 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004583 s32 err = 0;
4584
Arend van Sprield96b8012012-12-05 15:26:02 +01004585 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004586
Arend van Sprielc1179032012-10-22 13:55:33 -07004587 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4588 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004589 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004590 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004591 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004592 brcmf_update_bss_info(cfg, ifp);
4593 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4594 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004595 }
4596 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004597 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004598 conn_info->req_ie,
4599 conn_info->req_ie_len,
4600 conn_info->resp_ie,
4601 conn_info->resp_ie_len,
4602 completed ? WLAN_STATUS_SUCCESS :
4603 WLAN_STATUS_AUTH_TIMEOUT,
4604 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004605 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4606 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004607 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004608 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004609 return err;
4610}
4611
4612static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004613brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004614 struct net_device *ndev,
4615 const struct brcmf_event_msg *e, void *data)
4616{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004617 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004618 u32 event = e->event_code;
4619 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004620 struct station_info sinfo;
4621
Arend van Spriel16886732012-12-05 15:26:04 +01004622 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004623 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4624 ndev != cfg_to_ndev(cfg)) {
4625 brcmf_dbg(CONN, "AP mode link down\n");
4626 complete(&cfg->vif_disabled);
4627 return 0;
4628 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004629
Hante Meuleman1a873342012-09-27 14:17:54 +02004630 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004631 (reason == BRCMF_E_STATUS_SUCCESS)) {
4632 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004633 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4634 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004635 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004636 return -EINVAL;
4637 }
4638 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004639 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004640 generation++;
4641 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004642 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004643 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4644 (event == BRCMF_E_DEAUTH_IND) ||
4645 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004646 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004647 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004648 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004649}
4650
4651static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004652brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004653 const struct brcmf_event_msg *e, void *data)
4654{
Arend van Spriel19937322012-11-05 16:22:32 -08004655 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4656 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004657 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004658 s32 err = 0;
4659
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004660 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004661 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004662 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004663 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004664 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004665 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004666 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004667 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004668 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4669 &ifp->vif->sme_state);
4670 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4671 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004672 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004673 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004674 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004675 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004676 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004677 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004678 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004679 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004680 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004681 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004682 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004683 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004684 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004685 if (ndev != cfg_to_ndev(cfg))
4686 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004687 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004688 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004689 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4690 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004691 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004692 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004693 }
4694
4695 return err;
4696}
4697
4698static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004699brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004700 const struct brcmf_event_msg *e, void *data)
4701{
Arend van Spriel19937322012-11-05 16:22:32 -08004702 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004703 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004704 u32 event = e->event_code;
4705 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004706
4707 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004708 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004709 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004710 else
Arend van Spriel19937322012-11-05 16:22:32 -08004711 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004712 }
4713
4714 return err;
4715}
4716
4717static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004718brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004719 const struct brcmf_event_msg *e, void *data)
4720{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004721 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004722 enum nl80211_key_type key_type;
4723
4724 if (flags & BRCMF_EVENT_MSG_GROUP)
4725 key_type = NL80211_KEYTYPE_GROUP;
4726 else
4727 key_type = NL80211_KEYTYPE_PAIRWISE;
4728
Arend van Spriel19937322012-11-05 16:22:32 -08004729 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004730 NULL, GFP_KERNEL);
4731
4732 return 0;
4733}
4734
Arend van Sprield3c0b632013-02-08 15:53:37 +01004735static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4736 const struct brcmf_event_msg *e, void *data)
4737{
4738 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4739 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4740 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4741 struct brcmf_cfg80211_vif *vif;
4742
4743 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4744 ifevent->action, ifevent->flags, ifevent->ifidx,
4745 ifevent->bssidx);
4746
Arend van Sprield3c0b632013-02-08 15:53:37 +01004747 mutex_lock(&event->vif_event_lock);
4748 event->action = ifevent->action;
4749 vif = event->vif;
4750
4751 switch (ifevent->action) {
4752 case BRCMF_E_IF_ADD:
4753 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08004754 if (!cfg->vif_event.vif) {
4755 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004756 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08004757 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004758
4759 ifp->vif = vif;
4760 vif->ifp = ifp;
Arend van Spriel01b8e7d2013-04-05 10:57:51 +02004761 if (ifp->ndev) {
4762 vif->wdev.netdev = ifp->ndev;
4763 ifp->ndev->ieee80211_ptr = &vif->wdev;
4764 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4765 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004766 mutex_unlock(&event->vif_event_lock);
4767 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01004768 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004769
4770 case BRCMF_E_IF_DEL:
Arend van Sprield3c0b632013-02-08 15:53:37 +01004771 mutex_unlock(&event->vif_event_lock);
4772 /* event may not be upon user request */
4773 if (brcmf_cfg80211_vif_event_armed(cfg))
4774 wake_up(&event->vif_wq);
4775 return 0;
4776
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01004777 case BRCMF_E_IF_CHANGE:
4778 mutex_unlock(&event->vif_event_lock);
4779 wake_up(&event->vif_wq);
4780 return 0;
4781
Arend van Sprield3c0b632013-02-08 15:53:37 +01004782 default:
4783 mutex_unlock(&event->vif_event_lock);
4784 break;
4785 }
4786 return -EINVAL;
4787}
4788
Arend van Spriel5b435de2011-10-05 13:19:03 +02004789static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4790{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004791 conf->frag_threshold = (u32)-1;
4792 conf->rts_threshold = (u32)-1;
4793 conf->retry_short = (u32)-1;
4794 conf->retry_long = (u32)-1;
4795 conf->tx_power = -1;
4796}
4797
Arend van Spriel5c36b992012-11-14 18:46:05 -08004798static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004799{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004800 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4801 brcmf_notify_connect_status);
4802 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4803 brcmf_notify_connect_status);
4804 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4805 brcmf_notify_connect_status);
4806 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4807 brcmf_notify_connect_status);
4808 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4809 brcmf_notify_connect_status);
4810 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4811 brcmf_notify_connect_status);
4812 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4813 brcmf_notify_roaming_status);
4814 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4815 brcmf_notify_mic_status);
4816 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4817 brcmf_notify_connect_status);
4818 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4819 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004820 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4821 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004822 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004823 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004824 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4825 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01004826 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4827 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004828 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4829 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004830 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4831 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004832}
4833
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004834static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004835{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004836 kfree(cfg->conf);
4837 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004838 kfree(cfg->escan_ioctl_buf);
4839 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004840 kfree(cfg->extra_buf);
4841 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004842 kfree(cfg->pmk_list);
4843 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004844}
4845
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004846static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004847{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004848 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4849 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004850 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004851 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4852 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004853 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004854 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4855 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004856 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004857 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4858 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004859 goto init_priv_mem_out;
4860
4861 return 0;
4862
4863init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004864 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004865
4866 return -ENOMEM;
4867}
4868
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004869static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004870{
4871 s32 err = 0;
4872
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004873 cfg->scan_request = NULL;
4874 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004875 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004876 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004877 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004878 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004879 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004880 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004881 if (err)
4882 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004883 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004884 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004885 brcmf_init_escan(cfg);
4886 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004887 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004888 return err;
4889}
4890
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004891static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004892{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004893 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004894 brcmf_abort_scanning(cfg);
4895 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004896}
4897
Arend van Sprield3c0b632013-02-08 15:53:37 +01004898static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4899{
4900 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004901 mutex_init(&event->vif_event_lock);
4902}
4903
Arend van Sprield9cb2592012-12-05 15:25:54 +01004904struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4905 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004906{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004907 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004908 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004909 struct wiphy *wiphy;
4910 struct brcmf_cfg80211_vif *vif;
4911 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004912 s32 err = 0;
Franky Lin83cf17a2013-04-11 13:28:50 +02004913 s32 io_type;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004914
4915 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004916 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004917 return NULL;
4918 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004919
Arend van Spriel3eacf862012-10-22 13:55:30 -07004920 ifp = netdev_priv(ndev);
4921 wiphy = brcmf_setup_wiphy(busdev);
4922 if (IS_ERR(wiphy))
4923 return NULL;
4924
4925 cfg = wiphy_priv(wiphy);
4926 cfg->wiphy = wiphy;
4927 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004928 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004929 INIT_LIST_HEAD(&cfg->vif_list);
4930
Arend van Sprield3c0b632013-02-08 15:53:37 +01004931 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004932 if (IS_ERR(vif)) {
4933 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004934 return NULL;
4935 }
4936
Arend van Sprield3c0b632013-02-08 15:53:37 +01004937 vif->ifp = ifp;
4938 vif->wdev.netdev = ndev;
4939 ndev->ieee80211_ptr = &vif->wdev;
4940 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4941
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004942 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004943 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004944 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004945 goto cfg80211_attach_out;
4946 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004947 ifp->vif = vif;
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004948
4949 err = brcmf_p2p_attach(cfg);
4950 if (err) {
4951 brcmf_err("P2P initilisation failed (%d)\n", err);
4952 goto cfg80211_p2p_attach_out;
4953 }
Piotr Haber61730d42013-04-23 12:53:12 +02004954 err = brcmf_btcoex_attach(cfg);
4955 if (err) {
4956 brcmf_err("BT-coex initialisation failed (%d)\n", err);
4957 brcmf_p2p_detach(&cfg->p2p);
4958 goto cfg80211_p2p_attach_out;
4959 }
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004960
Arend van Spriel89c2f382013-08-10 12:27:25 +02004961 err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
4962 if (err) {
4963 brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
4964 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
4965 }
4966
Franky Lin83cf17a2013-04-11 13:28:50 +02004967 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
4968 &io_type);
4969 if (err) {
4970 brcmf_err("Failed to get D11 version (%d)\n", err);
4971 goto cfg80211_p2p_attach_out;
4972 }
4973 cfg->d11inf.io_type = (u8)io_type;
4974 brcmu_d11_attach(&cfg->d11inf);
4975
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004976 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004977
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004978cfg80211_p2p_attach_out:
4979 wl_deinit_priv(cfg);
4980
Arend van Spriel5b435de2011-10-05 13:19:03 +02004981cfg80211_attach_out:
Arend van Spriel24e28be2013-05-27 21:09:55 +02004982 brcmf_free_vif(cfg, vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004983 return NULL;
4984}
4985
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004986void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004987{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004988 struct brcmf_cfg80211_vif *vif;
4989 struct brcmf_cfg80211_vif *tmp;
4990
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004991 wl_deinit_priv(cfg);
Piotr Haber61730d42013-04-23 12:53:12 +02004992 brcmf_btcoex_detach(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004993 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
Arend van Spriel24e28be2013-05-27 21:09:55 +02004994 brcmf_free_vif(cfg, vif);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004995 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004996}
4997
Arend van Spriel5b435de2011-10-05 13:19:03 +02004998static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004999brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005000{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005001 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005002 __le32 roamtrigger[2];
5003 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005004
5005 /*
5006 * Setup timeout if Beacons are lost and roam is
5007 * off to report link down
5008 */
5009 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005010 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005011 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005012 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005013 goto dongle_rom_out;
5014 }
5015 }
5016
5017 /*
5018 * Enable/Disable built-in roaming to allow supplicant
5019 * to take care of roaming
5020 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005021 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07005022 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005023 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005024 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005025 goto dongle_rom_out;
5026 }
5027
Arend van Sprielf588bc02011-10-12 20:51:22 +02005028 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5029 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005030 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005031 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005032 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005033 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005034 goto dongle_rom_out;
5035 }
5036
Arend van Sprielf588bc02011-10-12 20:51:22 +02005037 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5038 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005039 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005040 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005041 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01005042 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005043 goto dongle_rom_out;
5044 }
5045
5046dongle_rom_out:
5047 return err;
5048}
5049
5050static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01005051brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005052 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005053{
5054 s32 err = 0;
5055
Arend van Sprielac24be62012-10-22 10:36:23 -07005056 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005057 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005058 if (err) {
5059 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005060 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005061 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005062 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005063 goto dongle_scantime_out;
5064 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005065 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005066 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005067 if (err) {
5068 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005069 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005070 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005071 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005072 goto dongle_scantime_out;
5073 }
5074
Arend van Sprielac24be62012-10-22 10:36:23 -07005075 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005076 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005077 if (err) {
5078 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005079 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02005080 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01005081 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005082 goto dongle_scantime_out;
5083 }
5084
5085dongle_scantime_out:
5086 return err;
5087}
5088
Hante Meulemand48200b2013-04-03 12:40:29 +02005089
5090static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
5091{
5092 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5093 struct ieee80211_channel *band_chan_arr;
5094 struct brcmf_chanspec_list *list;
Franky Lin83cf17a2013-04-11 13:28:50 +02005095 struct brcmu_chan ch;
Hante Meulemand48200b2013-04-03 12:40:29 +02005096 s32 err;
5097 u8 *pbuf;
5098 u32 i, j;
5099 u32 total;
Hante Meulemand48200b2013-04-03 12:40:29 +02005100 enum ieee80211_band band;
5101 u32 channel;
5102 u32 *n_cnt;
5103 bool ht40_allowed;
5104 u32 index;
5105 u32 ht40_flag;
5106 bool update;
5107 u32 array_size;
5108
5109 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
5110
5111 if (pbuf == NULL)
5112 return -ENOMEM;
5113
5114 list = (struct brcmf_chanspec_list *)pbuf;
5115
5116 err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
5117 BRCMF_DCMD_MEDLEN);
5118 if (err) {
5119 brcmf_err("get chanspecs error (%d)\n", err);
5120 goto exit;
5121 }
5122
5123 __wl_band_2ghz.n_channels = 0;
5124 __wl_band_5ghz_a.n_channels = 0;
5125
5126 total = le32_to_cpu(list->count);
5127 for (i = 0; i < total; i++) {
Franky Lin83cf17a2013-04-11 13:28:50 +02005128 ch.chspec = (u16)le32_to_cpu(list->element[i]);
5129 cfg->d11inf.decchspec(&ch);
Hante Meulemand48200b2013-04-03 12:40:29 +02005130
Franky Lin83cf17a2013-04-11 13:28:50 +02005131 if (ch.band == BRCMU_CHAN_BAND_2G) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005132 band_chan_arr = __wl_2ghz_channels;
5133 array_size = ARRAY_SIZE(__wl_2ghz_channels);
5134 n_cnt = &__wl_band_2ghz.n_channels;
5135 band = IEEE80211_BAND_2GHZ;
5136 ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
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;
5142 ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
5143 } else {
Franky Lin83cf17a2013-04-11 13:28:50 +02005144 brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec);
Hante Meulemand48200b2013-04-03 12:40:29 +02005145 continue;
5146 }
Franky Lin83cf17a2013-04-11 13:28:50 +02005147 if (!ht40_allowed && 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
Franky Lin83cf17a2013-04-11 13:28:50 +02005165 if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005166 /* assuming the order is HT20, HT40 Upper,
5167 * HT40 lower from chanspecs
5168 */
5169 ht40_flag = band_chan_arr[index].flags &
5170 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005171 if (ch.sb == BRCMU_CHAN_SB_U) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005172 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5173 band_chan_arr[index].flags &=
5174 ~IEEE80211_CHAN_NO_HT40;
5175 band_chan_arr[index].flags |=
5176 IEEE80211_CHAN_NO_HT40PLUS;
5177 } else {
5178 /* It should be one of
5179 * IEEE80211_CHAN_NO_HT40 or
5180 * IEEE80211_CHAN_NO_HT40PLUS
5181 */
5182 band_chan_arr[index].flags &=
5183 ~IEEE80211_CHAN_NO_HT40;
5184 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
5185 band_chan_arr[index].flags |=
5186 IEEE80211_CHAN_NO_HT40MINUS;
5187 }
5188 } else {
5189 band_chan_arr[index].flags =
5190 IEEE80211_CHAN_NO_HT40;
Franky Lin83cf17a2013-04-11 13:28:50 +02005191 ch.bw = BRCMU_CHAN_BW_20;
5192 cfg->d11inf.encchspec(&ch);
5193 channel = ch.chspec;
Hante Meulemand48200b2013-04-03 12:40:29 +02005194 err = brcmf_fil_bsscfg_int_get(ifp,
5195 "per_chan_info",
5196 &channel);
5197 if (!err) {
5198 if (channel & WL_CHAN_RADAR)
5199 band_chan_arr[index].flags |=
5200 (IEEE80211_CHAN_RADAR |
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005201 IEEE80211_CHAN_NO_IR);
Hante Meulemand48200b2013-04-03 12:40:29 +02005202 if (channel & WL_CHAN_PASSIVE)
5203 band_chan_arr[index].flags |=
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02005204 IEEE80211_CHAN_NO_IR;
Hante Meulemand48200b2013-04-03 12:40:29 +02005205 }
5206 }
5207 if (!update)
5208 (*n_cnt)++;
5209 }
5210 }
5211exit:
5212 kfree(pbuf);
5213 return err;
5214}
5215
5216
5217static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005218{
Arend van Sprielac24be62012-10-22 10:36:23 -07005219 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005220 struct wiphy *wiphy;
5221 s32 phy_list;
Hante Meulemand48200b2013-04-03 12:40:29 +02005222 u32 band_list[3];
5223 u32 nmode;
5224 u32 bw_cap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005225 s8 phy;
Hante Meulemand48200b2013-04-03 12:40:29 +02005226 s32 err;
5227 u32 nband;
5228 s32 i;
5229 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
5230 s32 index;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005231
Hante Meulemanb87e2c42012-11-14 18:46:23 -08005232 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005233 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005234 if (err) {
Hante Meulemand48200b2013-04-03 12:40:29 +02005235 brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005236 return err;
5237 }
5238
Hante Meuleman3ba81372012-09-19 22:21:13 +02005239 phy = ((char *)&phy_list)[0];
Hante Meulemand48200b2013-04-03 12:40:29 +02005240 brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
5241
5242
5243 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
5244 &band_list, sizeof(band_list));
5245 if (err) {
5246 brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
5247 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005248 }
Hante Meulemand48200b2013-04-03 12:40:29 +02005249 brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
5250 band_list[0], band_list[1], band_list[2]);
5251
5252 err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
5253 if (err) {
5254 brcmf_err("nmode error (%d)\n", err);
5255 } else {
5256 err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
5257 if (err)
5258 brcmf_err("mimo_bw_cap error (%d)\n", err);
5259 }
5260 brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
5261
5262 err = brcmf_construct_reginfo(cfg, bw_cap);
5263 if (err) {
5264 brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
5265 return err;
5266 }
5267
5268 nband = band_list[0];
5269 memset(bands, 0, sizeof(bands));
5270
5271 for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
5272 index = -1;
5273 if ((band_list[i] == WLC_BAND_5G) &&
5274 (__wl_band_5ghz_a.n_channels > 0)) {
5275 index = IEEE80211_BAND_5GHZ;
5276 bands[index] = &__wl_band_5ghz_a;
5277 if ((bw_cap == WLC_N_BW_40ALL) ||
5278 (bw_cap == WLC_N_BW_20IN2G_40IN5G))
5279 bands[index]->ht_cap.cap |=
5280 IEEE80211_HT_CAP_SGI_40;
5281 } else if ((band_list[i] == WLC_BAND_2G) &&
5282 (__wl_band_2ghz.n_channels > 0)) {
5283 index = IEEE80211_BAND_2GHZ;
5284 bands[index] = &__wl_band_2ghz;
5285 if (bw_cap == WLC_N_BW_40ALL)
5286 bands[index]->ht_cap.cap |=
5287 IEEE80211_HT_CAP_SGI_40;
5288 }
5289
5290 if ((index >= 0) && nmode) {
5291 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
5292 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
5293 bands[index]->ht_cap.ht_supported = true;
5294 bands[index]->ht_cap.ampdu_factor =
5295 IEEE80211_HT_MAX_AMPDU_64K;
5296 bands[index]->ht_cap.ampdu_density =
5297 IEEE80211_HT_MPDU_DENSITY_16;
5298 /* An HT shall support all EQM rates for one spatial
5299 * stream
5300 */
5301 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
5302 }
5303 }
5304
5305 wiphy = cfg_to_wiphy(cfg);
5306 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
5307 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
5308 wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005309
5310 return err;
5311}
5312
Hante Meulemand48200b2013-04-03 12:40:29 +02005313
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005314static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005315{
Hante Meulemand48200b2013-04-03 12:40:29 +02005316 return brcmf_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005317}
5318
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005319static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005320{
5321 struct net_device *ndev;
5322 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01005323 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005324 s32 power_mode;
5325 s32 err = 0;
5326
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005327 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005328 return err;
5329
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005330 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005331 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01005332 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005333
Hante Meuleman40a23292013-01-02 15:22:51 +01005334 /* make sure RF is ready for work */
5335 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5336
5337 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
5338 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005339
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005340 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01005341 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005342 if (err)
5343 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01005344 brcmf_dbg(INFO, "power save set to %s\n",
5345 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005346
Hante Meuleman40a23292013-01-02 15:22:51 +01005347 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005348 if (err)
5349 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07005350 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5351 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01005352 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005353 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005354 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005355 if (err)
5356 goto default_conf_out;
5357
Hante Meulemanb3657452013-05-27 21:09:53 +02005358 brcmf_configure_arp_offload(ifp, true);
5359
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005360 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01005361default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005362
5363 return err;
5364
5365}
5366
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005367static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005368{
Arend van Sprielc1179032012-10-22 13:55:33 -07005369 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005370
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005371 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005372}
5373
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005374static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005375{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005376 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07005377
Arend van Spriel5b435de2011-10-05 13:19:03 +02005378 /*
5379 * While going down, if associated with AP disassociate
5380 * from AP to save power
5381 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005382 if (check_vif_up(ifp->vif)) {
5383 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005384
5385 /* Make sure WPA_Supplicant receives all the event
5386 generated due to DISASSOC call to the fw to keep
5387 the state fw and WPA_Supplicant state consistent
5388 */
5389 brcmf_delay(500);
5390 }
5391
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005392 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005393 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005394
Arend van Spriel5b435de2011-10-05 13:19:03 +02005395 return 0;
5396}
5397
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005398s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005399{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005400 struct brcmf_if *ifp = netdev_priv(ndev);
5401 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005402 s32 err = 0;
5403
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005404 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005405 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005406 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005407
5408 return err;
5409}
5410
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005411s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005412{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005413 struct brcmf_if *ifp = netdev_priv(ndev);
5414 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005415 s32 err = 0;
5416
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005417 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005418 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005419 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005420
5421 return err;
5422}
5423
Arend van Spriela7965fb2013-04-11 17:08:37 +02005424enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
5425{
5426 struct wireless_dev *wdev = &ifp->vif->wdev;
5427
5428 return wdev->iftype;
5429}
5430
Arend van Spriel9f440b72013-02-08 15:53:36 +01005431u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5432{
5433 struct brcmf_cfg80211_vif *vif;
5434 bool result = 0;
5435
5436 list_for_each_entry(vif, &cfg->vif_list, list) {
5437 if (test_bit(state, &vif->sme_state))
5438 result++;
5439 }
5440 return result;
5441}
Arend van Sprield3c0b632013-02-08 15:53:37 +01005442
5443static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5444 u8 action)
5445{
5446 u8 evt_action;
5447
5448 mutex_lock(&event->vif_event_lock);
5449 evt_action = event->action;
5450 mutex_unlock(&event->vif_event_lock);
5451 return evt_action == action;
5452}
5453
5454void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5455 struct brcmf_cfg80211_vif *vif)
5456{
5457 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5458
5459 mutex_lock(&event->vif_event_lock);
5460 event->vif = vif;
5461 event->action = 0;
5462 mutex_unlock(&event->vif_event_lock);
5463}
5464
5465bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5466{
5467 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5468 bool armed;
5469
5470 mutex_lock(&event->vif_event_lock);
5471 armed = event->vif != NULL;
5472 mutex_unlock(&event->vif_event_lock);
5473
5474 return armed;
5475}
5476int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5477 u8 action, ulong timeout)
5478{
5479 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5480
5481 return wait_event_timeout(event->vif_wq,
5482 vif_event_equals(event, action), timeout);
5483}
5484