blob: 2af9c0f0798d9e5cc2e484b0599a7d50aede68e5 [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"
Hante Meuleman7a5c1f62013-02-08 15:53:44 +010029#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010030#include "p2p.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020031#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070032#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020033
Arend van Spriele5806072012-09-19 22:21:08 +020034#define BRCMF_SCAN_IE_LEN_MAX 2048
35#define BRCMF_PNO_VERSION 2
36#define BRCMF_PNO_TIME 30
37#define BRCMF_PNO_REPEAT 4
38#define BRCMF_PNO_FREQ_EXPO_MAX 3
39#define BRCMF_PNO_MAX_PFN_COUNT 16
40#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
41#define BRCMF_PNO_HIDDEN_BIT 2
42#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
43#define BRCMF_PNO_SCAN_COMPLETE 1
44#define BRCMF_PNO_SCAN_INCOMPLETE 0
45
Arend van Spriel9f440b72013-02-08 15:53:36 +010046#define BRCMF_IFACE_MAX_CNT 3
Arend van Spriel3eacf862012-10-22 13:55:30 -070047
Hante Meuleman1a873342012-09-27 14:17:54 +020048#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
49#define WPA_OUI_TYPE 1
50#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
51#define WME_OUI_TYPE 2
Hante Meuleman89286dc2013-02-08 15:53:46 +010052#define WPS_OUI_TYPE 4
Hante Meuleman1a873342012-09-27 14:17:54 +020053
54#define VS_IE_FIXED_HDR_LEN 6
55#define WPA_IE_VERSION_LEN 2
56#define WPA_IE_MIN_OUI_LEN 4
57#define WPA_IE_SUITE_COUNT_LEN 2
58
59#define WPA_CIPHER_NONE 0 /* None */
60#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
61#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
62#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
63#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
64
65#define RSN_AKM_NONE 0 /* None (IBSS) */
66#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
67#define RSN_AKM_PSK 2 /* Pre-shared Key */
68#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
69#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
70
71#define VNDR_IE_CMD_LEN 4 /* length of the set command
72 * string :"add", "del" (+ NUL)
73 */
74#define VNDR_IE_COUNT_OFFSET 4
75#define VNDR_IE_PKTFLAG_OFFSET 8
76#define VNDR_IE_VSIE_OFFSET 12
77#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010078#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020079
80#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
81#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020082
Hante Meuleman89286dc2013-02-08 15:53:46 +010083#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
84#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
85#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
86
Arend van Spriel5b435de2011-10-05 13:19:03 +020087#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
88 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
89
Arend van Sprielce81e312012-10-22 13:55:37 -070090static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020091{
Arend van Sprielc1179032012-10-22 13:55:33 -070092 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +010093 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
94 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +020095 return false;
96 }
97 return true;
98}
99
100#define CHAN2G(_channel, _freq, _flags) { \
101 .band = IEEE80211_BAND_2GHZ, \
102 .center_freq = (_freq), \
103 .hw_value = (_channel), \
104 .flags = (_flags), \
105 .max_antenna_gain = 0, \
106 .max_power = 30, \
107}
108
109#define CHAN5G(_channel, _flags) { \
110 .band = IEEE80211_BAND_5GHZ, \
111 .center_freq = 5000 + (5 * (_channel)), \
112 .hw_value = (_channel), \
113 .flags = (_flags), \
114 .max_antenna_gain = 0, \
115 .max_power = 30, \
116}
117
118#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
119#define RATETAB_ENT(_rateid, _flags) \
120 { \
121 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
122 .hw_value = (_rateid), \
123 .flags = (_flags), \
124 }
125
126static struct ieee80211_rate __wl_rates[] = {
127 RATETAB_ENT(BRCM_RATE_1M, 0),
128 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
129 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
130 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
131 RATETAB_ENT(BRCM_RATE_6M, 0),
132 RATETAB_ENT(BRCM_RATE_9M, 0),
133 RATETAB_ENT(BRCM_RATE_12M, 0),
134 RATETAB_ENT(BRCM_RATE_18M, 0),
135 RATETAB_ENT(BRCM_RATE_24M, 0),
136 RATETAB_ENT(BRCM_RATE_36M, 0),
137 RATETAB_ENT(BRCM_RATE_48M, 0),
138 RATETAB_ENT(BRCM_RATE_54M, 0),
139};
140
141#define wl_a_rates (__wl_rates + 4)
142#define wl_a_rates_size 8
143#define wl_g_rates (__wl_rates + 0)
144#define wl_g_rates_size 12
145
146static struct ieee80211_channel __wl_2ghz_channels[] = {
147 CHAN2G(1, 2412, 0),
148 CHAN2G(2, 2417, 0),
149 CHAN2G(3, 2422, 0),
150 CHAN2G(4, 2427, 0),
151 CHAN2G(5, 2432, 0),
152 CHAN2G(6, 2437, 0),
153 CHAN2G(7, 2442, 0),
154 CHAN2G(8, 2447, 0),
155 CHAN2G(9, 2452, 0),
156 CHAN2G(10, 2457, 0),
157 CHAN2G(11, 2462, 0),
158 CHAN2G(12, 2467, 0),
159 CHAN2G(13, 2472, 0),
160 CHAN2G(14, 2484, 0),
161};
162
163static struct ieee80211_channel __wl_5ghz_a_channels[] = {
164 CHAN5G(34, 0), CHAN5G(36, 0),
165 CHAN5G(38, 0), CHAN5G(40, 0),
166 CHAN5G(42, 0), CHAN5G(44, 0),
167 CHAN5G(46, 0), CHAN5G(48, 0),
168 CHAN5G(52, 0), CHAN5G(56, 0),
169 CHAN5G(60, 0), CHAN5G(64, 0),
170 CHAN5G(100, 0), CHAN5G(104, 0),
171 CHAN5G(108, 0), CHAN5G(112, 0),
172 CHAN5G(116, 0), CHAN5G(120, 0),
173 CHAN5G(124, 0), CHAN5G(128, 0),
174 CHAN5G(132, 0), CHAN5G(136, 0),
175 CHAN5G(140, 0), CHAN5G(149, 0),
176 CHAN5G(153, 0), CHAN5G(157, 0),
177 CHAN5G(161, 0), CHAN5G(165, 0),
178 CHAN5G(184, 0), CHAN5G(188, 0),
179 CHAN5G(192, 0), CHAN5G(196, 0),
180 CHAN5G(200, 0), CHAN5G(204, 0),
181 CHAN5G(208, 0), CHAN5G(212, 0),
182 CHAN5G(216, 0),
183};
184
185static struct ieee80211_channel __wl_5ghz_n_channels[] = {
186 CHAN5G(32, 0), CHAN5G(34, 0),
187 CHAN5G(36, 0), CHAN5G(38, 0),
188 CHAN5G(40, 0), CHAN5G(42, 0),
189 CHAN5G(44, 0), CHAN5G(46, 0),
190 CHAN5G(48, 0), CHAN5G(50, 0),
191 CHAN5G(52, 0), CHAN5G(54, 0),
192 CHAN5G(56, 0), CHAN5G(58, 0),
193 CHAN5G(60, 0), CHAN5G(62, 0),
194 CHAN5G(64, 0), CHAN5G(66, 0),
195 CHAN5G(68, 0), CHAN5G(70, 0),
196 CHAN5G(72, 0), CHAN5G(74, 0),
197 CHAN5G(76, 0), CHAN5G(78, 0),
198 CHAN5G(80, 0), CHAN5G(82, 0),
199 CHAN5G(84, 0), CHAN5G(86, 0),
200 CHAN5G(88, 0), CHAN5G(90, 0),
201 CHAN5G(92, 0), CHAN5G(94, 0),
202 CHAN5G(96, 0), CHAN5G(98, 0),
203 CHAN5G(100, 0), CHAN5G(102, 0),
204 CHAN5G(104, 0), CHAN5G(106, 0),
205 CHAN5G(108, 0), CHAN5G(110, 0),
206 CHAN5G(112, 0), CHAN5G(114, 0),
207 CHAN5G(116, 0), CHAN5G(118, 0),
208 CHAN5G(120, 0), CHAN5G(122, 0),
209 CHAN5G(124, 0), CHAN5G(126, 0),
210 CHAN5G(128, 0), CHAN5G(130, 0),
211 CHAN5G(132, 0), CHAN5G(134, 0),
212 CHAN5G(136, 0), CHAN5G(138, 0),
213 CHAN5G(140, 0), CHAN5G(142, 0),
214 CHAN5G(144, 0), CHAN5G(145, 0),
215 CHAN5G(146, 0), CHAN5G(147, 0),
216 CHAN5G(148, 0), CHAN5G(149, 0),
217 CHAN5G(150, 0), CHAN5G(151, 0),
218 CHAN5G(152, 0), CHAN5G(153, 0),
219 CHAN5G(154, 0), CHAN5G(155, 0),
220 CHAN5G(156, 0), CHAN5G(157, 0),
221 CHAN5G(158, 0), CHAN5G(159, 0),
222 CHAN5G(160, 0), CHAN5G(161, 0),
223 CHAN5G(162, 0), CHAN5G(163, 0),
224 CHAN5G(164, 0), CHAN5G(165, 0),
225 CHAN5G(166, 0), CHAN5G(168, 0),
226 CHAN5G(170, 0), CHAN5G(172, 0),
227 CHAN5G(174, 0), CHAN5G(176, 0),
228 CHAN5G(178, 0), CHAN5G(180, 0),
229 CHAN5G(182, 0), CHAN5G(184, 0),
230 CHAN5G(186, 0), CHAN5G(188, 0),
231 CHAN5G(190, 0), CHAN5G(192, 0),
232 CHAN5G(194, 0), CHAN5G(196, 0),
233 CHAN5G(198, 0), CHAN5G(200, 0),
234 CHAN5G(202, 0), CHAN5G(204, 0),
235 CHAN5G(206, 0), CHAN5G(208, 0),
236 CHAN5G(210, 0), CHAN5G(212, 0),
237 CHAN5G(214, 0), CHAN5G(216, 0),
238 CHAN5G(218, 0), CHAN5G(220, 0),
239 CHAN5G(222, 0), CHAN5G(224, 0),
240 CHAN5G(226, 0), CHAN5G(228, 0),
241};
242
243static struct ieee80211_supported_band __wl_band_2ghz = {
244 .band = IEEE80211_BAND_2GHZ,
245 .channels = __wl_2ghz_channels,
246 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
247 .bitrates = wl_g_rates,
248 .n_bitrates = wl_g_rates_size,
249};
250
251static struct ieee80211_supported_band __wl_band_5ghz_a = {
252 .band = IEEE80211_BAND_5GHZ,
253 .channels = __wl_5ghz_a_channels,
254 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
255 .bitrates = wl_a_rates,
256 .n_bitrates = wl_a_rates_size,
257};
258
259static struct ieee80211_supported_band __wl_band_5ghz_n = {
260 .band = IEEE80211_BAND_5GHZ,
261 .channels = __wl_5ghz_n_channels,
262 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
263 .bitrates = wl_a_rates,
264 .n_bitrates = wl_a_rates_size,
265};
266
267static const u32 __wl_cipher_suites[] = {
268 WLAN_CIPHER_SUITE_WEP40,
269 WLAN_CIPHER_SUITE_WEP104,
270 WLAN_CIPHER_SUITE_TKIP,
271 WLAN_CIPHER_SUITE_CCMP,
272 WLAN_CIPHER_SUITE_AES_CMAC,
273};
274
Hante Meuleman1a873342012-09-27 14:17:54 +0200275/* Vendor specific ie. id = 221, oui and type defines exact ie */
276struct brcmf_vs_tlv {
277 u8 id;
278 u8 len;
279 u8 oui[3];
280 u8 oui_type;
281};
282
283struct parsed_vndr_ie_info {
284 u8 *ie_ptr;
285 u32 ie_len; /* total length including id & length field */
286 struct brcmf_vs_tlv vndrie;
287};
288
289struct parsed_vndr_ies {
290 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100291 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200292};
293
Alwin Beukersef6ac172011-10-12 20:51:26 +0200294/* Quarter dBm units to mW
295 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
296 * Table is offset so the last entry is largest mW value that fits in
297 * a u16.
298 */
299
300#define QDBM_OFFSET 153 /* Offset for first entry */
301#define QDBM_TABLE_LEN 40 /* Table size */
302
303/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
304 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
305 */
306#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
307
308/* Largest mW value that will round down to the last table entry,
309 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
310 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
311 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
312 */
313#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
314
315static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
316/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
317/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
318/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
319/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
320/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
321/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
322};
323
324static u16 brcmf_qdbm_to_mw(u8 qdbm)
325{
326 uint factor = 1;
327 int idx = qdbm - QDBM_OFFSET;
328
329 if (idx >= QDBM_TABLE_LEN)
330 /* clamp to max u16 mW value */
331 return 0xFFFF;
332
333 /* scale the qdBm index up to the range of the table 0-40
334 * where an offset of 40 qdBm equals a factor of 10 mW.
335 */
336 while (idx < 0) {
337 idx += 40;
338 factor *= 10;
339 }
340
341 /* return the mW value scaled down to the correct factor of 10,
342 * adding in factor/2 to get proper rounding.
343 */
344 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
345}
346
347static u8 brcmf_mw_to_qdbm(u16 mw)
348{
349 u8 qdbm;
350 int offset;
351 uint mw_uint = mw;
352 uint boundary;
353
354 /* handle boundary case */
355 if (mw_uint <= 1)
356 return 0;
357
358 offset = QDBM_OFFSET;
359
360 /* move mw into the range of the table */
361 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
362 mw_uint *= 10;
363 offset -= 40;
364 }
365
366 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
367 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
368 nqdBm_to_mW_map[qdbm]) / 2;
369 if (mw_uint < boundary)
370 break;
371 }
372
373 qdbm += (u8) offset;
374
375 return qdbm;
376}
377
Arend van Spriel9f440b72013-02-08 15:53:36 +0100378u16 channel_to_chanspec(struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700379{
380 u16 chanspec;
381
382 chanspec = ieee80211_frequency_to_channel(ch->center_freq);
383 chanspec &= WL_CHANSPEC_CHAN_MASK;
384
385 if (ch->band == IEEE80211_BAND_2GHZ)
386 chanspec |= WL_CHANSPEC_BAND_2G;
387 else
388 chanspec |= WL_CHANSPEC_BAND_5G;
389
Hante Meuleman17012612013-02-06 18:40:44 +0100390 chanspec |= WL_CHANSPEC_BW_20;
391 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
392
Arend van Spriel6e186162012-10-22 10:36:22 -0700393 return chanspec;
394}
395
Hante Meuleman89286dc2013-02-08 15:53:46 +0100396/* Traverse a string of 1-byte tag/1-byte length/variable-length value
397 * triples, returning a pointer to the substring whose first element
398 * matches tag
399 */
400struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
401{
402 struct brcmf_tlv *elt;
403 int totlen;
404
405 elt = (struct brcmf_tlv *)buf;
406 totlen = buflen;
407
408 /* find tagged parameter */
409 while (totlen >= TLV_HDR_LEN) {
410 int len = elt->len;
411
412 /* validate remaining totlen */
413 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
414 return elt;
415
416 elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
417 totlen -= (len + TLV_HDR_LEN);
418 }
419
420 return NULL;
421}
422
423/* Is any of the tlvs the expected entry? If
424 * not update the tlvs buffer pointer/length.
425 */
426static bool
427brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
428 u8 *oui, u32 oui_len, u8 type)
429{
430 /* If the contents match the OUI and the type */
431 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
432 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
433 type == ie[TLV_BODY_OFF + oui_len]) {
434 return true;
435 }
436
437 if (tlvs == NULL)
438 return false;
439 /* point to the next ie */
440 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
441 /* calculate the length of the rest of the buffer */
442 *tlvs_len -= (int)(ie - *tlvs);
443 /* update the pointer to the start of the buffer */
444 *tlvs = ie;
445
446 return false;
447}
448
449static struct brcmf_vs_tlv *
450brcmf_find_wpaie(u8 *parse, u32 len)
451{
452 struct brcmf_tlv *ie;
453
454 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
455 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
456 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
457 return (struct brcmf_vs_tlv *)ie;
458 }
459 return NULL;
460}
461
462static struct brcmf_vs_tlv *
463brcmf_find_wpsie(u8 *parse, u32 len)
464{
465 struct brcmf_tlv *ie;
466
467 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
468 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
469 WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
470 return (struct brcmf_vs_tlv *)ie;
471 }
472 return NULL;
473}
474
475
Arend van Spriel5b435de2011-10-05 13:19:03 +0200476static void convert_key_from_CPU(struct brcmf_wsec_key *key,
477 struct brcmf_wsec_key_le *key_le)
478{
479 key_le->index = cpu_to_le32(key->index);
480 key_le->len = cpu_to_le32(key->len);
481 key_le->algo = cpu_to_le32(key->algo);
482 key_le->flags = cpu_to_le32(key->flags);
483 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
484 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
485 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
486 memcpy(key_le->data, key->data, sizeof(key->data));
487 memcpy(key_le->ea, key->ea, sizeof(key->ea));
488}
489
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200490static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700491send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200492{
493 int err;
494 struct brcmf_wsec_key_le key_le;
495
496 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200497
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700498 brcmf_netdev_wait_pend8021x(ndev);
499
Arend van Sprielac24be62012-10-22 10:36:23 -0700500 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700501 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200502
Arend van Spriel5b435de2011-10-05 13:19:03 +0200503 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100504 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200505 return err;
506}
507
Arend van Spriel9f440b72013-02-08 15:53:36 +0100508static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
509 const char *name,
510 enum nl80211_iftype type,
511 u32 *flags,
512 struct vif_params *params)
513{
514 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
515 switch (type) {
516 case NL80211_IFTYPE_ADHOC:
517 case NL80211_IFTYPE_STATION:
518 case NL80211_IFTYPE_AP:
519 case NL80211_IFTYPE_AP_VLAN:
520 case NL80211_IFTYPE_WDS:
521 case NL80211_IFTYPE_MONITOR:
522 case NL80211_IFTYPE_MESH_POINT:
523 return ERR_PTR(-EOPNOTSUPP);
524 case NL80211_IFTYPE_P2P_CLIENT:
525 case NL80211_IFTYPE_P2P_GO:
526 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
527 case NL80211_IFTYPE_UNSPECIFIED:
528 case NL80211_IFTYPE_P2P_DEVICE:
529 default:
530 return ERR_PTR(-EINVAL);
531 }
532}
533
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100534void brcmf_set_mpc(struct net_device *ndev, int mpc)
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100535{
536 struct brcmf_if *ifp = netdev_priv(ndev);
537 s32 err = 0;
538
539 if (check_vif_up(ifp->vif)) {
540 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
541 if (err) {
542 brcmf_err("fail to set mpc\n");
543 return;
544 }
545 brcmf_dbg(INFO, "MPC : %d\n", mpc);
546 }
547}
548
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100549s32
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100550brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
551 struct net_device *ndev,
552 bool aborted, bool fw_abort)
553{
554 struct brcmf_scan_params_le params_le;
555 struct cfg80211_scan_request *scan_request;
556 s32 err = 0;
557
558 brcmf_dbg(SCAN, "Enter\n");
559
560 /* clear scan request, because the FW abort can cause a second call */
561 /* to this functon and might cause a double cfg80211_scan_done */
562 scan_request = cfg->scan_request;
563 cfg->scan_request = NULL;
564
565 if (timer_pending(&cfg->escan_timeout))
566 del_timer_sync(&cfg->escan_timeout);
567
568 if (fw_abort) {
569 /* Do a scan abort to stop the driver's scan engine */
570 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
571 memset(&params_le, 0, sizeof(params_le));
572 memset(params_le.bssid, 0xFF, ETH_ALEN);
573 params_le.bss_type = DOT11_BSSTYPE_ANY;
574 params_le.scan_type = 0;
575 params_le.channel_num = cpu_to_le32(1);
576 params_le.nprobes = cpu_to_le32(1);
577 params_le.active_time = cpu_to_le32(-1);
578 params_le.passive_time = cpu_to_le32(-1);
579 params_le.home_time = cpu_to_le32(-1);
580 /* Scan is aborted by setting channel_list[0] to -1 */
581 params_le.channel_list[0] = cpu_to_le16(-1);
582 /* E-Scan (or anyother type) can be aborted by SCAN */
583 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
584 &params_le, sizeof(params_le));
585 if (err)
586 brcmf_err("Scan abort failed\n");
587 }
588 /*
589 * e-scan can be initiated by scheduled scan
590 * which takes precedence.
591 */
592 if (cfg->sched_escan) {
593 brcmf_dbg(SCAN, "scheduled scan completed\n");
594 cfg->sched_escan = false;
595 if (!aborted)
596 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
597 brcmf_set_mpc(ndev, 1);
598 } else if (scan_request) {
599 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
600 aborted ? "Aborted" : "Done");
601 cfg80211_scan_done(scan_request, aborted);
602 brcmf_set_mpc(ndev, 1);
603 }
Hante Meuleman6eda4e22013-02-08 15:54:02 +0100604 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
605 brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100606
607 return err;
608}
609
Arend van Spriel9f440b72013-02-08 15:53:36 +0100610static
611int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
612{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100613 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
614 struct net_device *ndev = wdev->netdev;
615
616 /* vif event pending in firmware */
617 if (brcmf_cfg80211_vif_event_armed(cfg))
618 return -EBUSY;
619
620 if (ndev) {
621 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
622 cfg->escan_info.ndev == ndev)
623 brcmf_notify_escan_complete(cfg, ndev, true,
624 true);
625
626 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
627 }
628
Arend van Spriel9f440b72013-02-08 15:53:36 +0100629 switch (wdev->iftype) {
630 case NL80211_IFTYPE_ADHOC:
631 case NL80211_IFTYPE_STATION:
632 case NL80211_IFTYPE_AP:
633 case NL80211_IFTYPE_AP_VLAN:
634 case NL80211_IFTYPE_WDS:
635 case NL80211_IFTYPE_MONITOR:
636 case NL80211_IFTYPE_MESH_POINT:
637 return -EOPNOTSUPP;
638 case NL80211_IFTYPE_P2P_CLIENT:
639 case NL80211_IFTYPE_P2P_GO:
640 return brcmf_p2p_del_vif(wiphy, wdev);
641 case NL80211_IFTYPE_UNSPECIFIED:
642 case NL80211_IFTYPE_P2P_DEVICE:
643 default:
644 return -EINVAL;
645 }
646 return -EOPNOTSUPP;
647}
648
Arend van Spriel5b435de2011-10-05 13:19:03 +0200649static s32
650brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
651 enum nl80211_iftype type, u32 *flags,
652 struct vif_params *params)
653{
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100654 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -0700655 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100656 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200657 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200658 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200659 s32 err = 0;
660
Arend van Sprield96b8012012-12-05 15:26:02 +0100661 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200662
663 switch (type) {
664 case NL80211_IFTYPE_MONITOR:
665 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100666 brcmf_err("type (%d) : currently we do not support this type\n",
667 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200668 return -EOPNOTSUPP;
669 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100670 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200671 infra = 0;
672 break;
673 case NL80211_IFTYPE_STATION:
Hante Meuleman1bc7c652013-02-08 15:53:56 +0100674 /* Ignore change for p2p IF. Unclear why supplicant does this */
675 if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
676 (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
677 brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
678 /* WAR: It is unexpected to get a change of VIF for P2P
679 * IF, but it happens. The request can not be handled
680 * but returning EPERM causes a crash. Returning 0
681 * without setting ieee80211_ptr->iftype causes trace
682 * (WARN_ON) but it works with wpa_supplicant
683 */
684 return 0;
685 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100686 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200687 infra = 1;
688 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200689 case NL80211_IFTYPE_AP:
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100690 case NL80211_IFTYPE_P2P_GO:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100691 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200692 ap = 1;
693 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200694 default:
695 err = -EINVAL;
696 goto done;
697 }
698
Hante Meuleman1a873342012-09-27 14:17:54 +0200699 if (ap) {
Hante Meuleman7a5c1f62013-02-08 15:53:44 +0100700 if (type == NL80211_IFTYPE_P2P_GO) {
701 brcmf_dbg(INFO, "IF Type = P2P GO\n");
702 err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
703 }
704 if (!err) {
705 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
706 brcmf_dbg(INFO, "IF Type = AP\n");
707 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200708 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100709 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200710 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100711 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200712 err = -EAGAIN;
713 goto done;
714 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100715 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
716 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200717 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200718 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200719
720done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100721 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200722
723 return err;
724}
725
Hante Meulemane756af52012-09-11 21:18:52 +0200726static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
727 struct cfg80211_scan_request *request)
728{
729 u32 n_ssids;
730 u32 n_channels;
731 s32 i;
732 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200733 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200734 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200735 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200736
Arend van Sprielba40d162012-10-22 13:55:38 -0700737 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200738 params_le->bss_type = DOT11_BSSTYPE_ANY;
739 params_le->scan_type = 0;
740 params_le->channel_num = 0;
741 params_le->nprobes = cpu_to_le32(-1);
742 params_le->active_time = cpu_to_le32(-1);
743 params_le->passive_time = cpu_to_le32(-1);
744 params_le->home_time = cpu_to_le32(-1);
745 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
746
747 /* if request is null exit so it will be all channel broadcast scan */
748 if (!request)
749 return;
750
751 n_ssids = request->n_ssids;
752 n_channels = request->n_channels;
753 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100754 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
755 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200756 if (n_channels > 0) {
757 for (i = 0; i < n_channels; i++) {
Arend van Spriel6e186162012-10-22 10:36:22 -0700758 chanspec = channel_to_chanspec(request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100759 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
760 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200761 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200762 }
763 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100764 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200765 }
766 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100767 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200768 if (n_ssids > 0) {
769 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
770 n_channels * sizeof(u16);
771 offset = roundup(offset, sizeof(u32));
772 ptr = (char *)params_le + offset;
773 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200774 memset(&ssid_le, 0, sizeof(ssid_le));
775 ssid_le.SSID_len =
776 cpu_to_le32(request->ssids[i].ssid_len);
777 memcpy(ssid_le.SSID, request->ssids[i].ssid,
778 request->ssids[i].ssid_len);
779 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100780 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200781 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100782 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
783 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200784 memcpy(ptr, &ssid_le, sizeof(ssid_le));
785 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200786 }
787 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100788 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200789 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100790 brcmf_dbg(SCAN, "SSID %s len=%d\n",
791 params_le->ssid_le.SSID,
792 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200793 params_le->ssid_le.SSID_len =
794 cpu_to_le32(request->ssids->ssid_len);
795 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
796 request->ssids->ssid_len);
797 }
798 }
799 /* Adding mask to channel numbers */
800 params_le->channel_num =
801 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
802 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
803}
804
805static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200806brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
Hante Meulemane756af52012-09-11 21:18:52 +0200807 struct cfg80211_scan_request *request, u16 action)
808{
809 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
810 offsetof(struct brcmf_escan_params_le, params_le);
811 struct brcmf_escan_params_le *params;
812 s32 err = 0;
813
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100814 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200815
816 if (request != NULL) {
817 /* Allocate space for populating ssids in struct */
818 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
819
820 /* Allocate space for populating ssids in struct */
821 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
822 }
823
824 params = kzalloc(params_size, GFP_KERNEL);
825 if (!params) {
826 err = -ENOMEM;
827 goto exit;
828 }
829 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
830 brcmf_escan_prep(&params->params_le, request);
831 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
832 params->action = cpu_to_le16(action);
833 params->sync_id = cpu_to_le16(0x1234);
834
Arend van Sprielac24be62012-10-22 10:36:23 -0700835 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
836 params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200837 if (err) {
838 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100839 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200840 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100841 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200842 }
843
844 kfree(params);
845exit:
846 return err;
847}
848
849static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200850brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Hante Meulemane756af52012-09-11 21:18:52 +0200851 struct net_device *ndev, struct cfg80211_scan_request *request)
852{
853 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700854 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200855 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100856 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200857
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100858 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriel9f440b72013-02-08 15:53:36 +0100859 escan->ndev = ndev;
860 escan->wiphy = wiphy;
861 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700862 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700863 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700864 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200865 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100866 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200867 return err;
868 }
869 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200870 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200871 results->version = 0;
872 results->count = 0;
873 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
874
Arend van Spriel9f440b72013-02-08 15:53:36 +0100875 err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200876 if (err)
877 brcmf_set_mpc(ndev, 1);
878 return err;
879}
880
881static s32
882brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
883 struct cfg80211_scan_request *request,
884 struct cfg80211_ssid *this_ssid)
885{
Arend van Sprielc1179032012-10-22 13:55:33 -0700886 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200887 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Hante Meulemane756af52012-09-11 21:18:52 +0200888 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800889 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700890 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200891 bool escan_req;
892 bool spec_scan;
893 s32 err;
894 u32 SSID_len;
895
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100896 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200897
Arend van Sprielc1179032012-10-22 13:55:33 -0700898 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100899 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200900 return -EAGAIN;
901 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700902 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100903 brcmf_err("Scanning being aborted: status (%lu)\n",
904 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200905 return -EAGAIN;
906 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700907 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100908 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200909 return -EAGAIN;
910 }
911
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100912 /* If scan req comes for p2p0, send it over primary I/F */
913 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
914 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
915 ndev = ifp->ndev;
916 }
917
Hante Meulemane756af52012-09-11 21:18:52 +0200918 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200919 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200920 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
921
922 escan_req = false;
923 if (request) {
924 /* scan bss */
925 ssids = request->ssids;
926 escan_req = true;
927 } else {
928 /* scan in ibss */
929 /* we don't do escan in ibss */
930 ssids = this_ssid;
931 }
932
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200933 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700934 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200935 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100936 cfg->escan_info.run = brcmf_run_escan;
Hante Meuleman0f8ffe12013-02-08 15:53:42 +0100937 err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100938 if (err)
939 goto scan_out;
940
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200941 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800942 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200943 goto scan_out;
944 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100945 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
946 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200947 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
948 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
949 sr->ssid_le.SSID_len = cpu_to_le32(0);
950 spec_scan = false;
951 if (SSID_len) {
952 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
953 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
954 spec_scan = true;
955 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100956 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200957
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700958 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700959 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700960 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200961 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100962 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200963 goto scan_out;
964 }
965 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700966 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700967 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200968 if (err) {
969 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100970 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
971 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200972 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100973 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200974
975 brcmf_set_mpc(ndev, 1);
976 goto scan_out;
977 }
978 }
979
980 return 0;
981
982scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700983 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200984 if (timer_pending(&cfg->escan_timeout))
985 del_timer_sync(&cfg->escan_timeout);
986 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200987 return err;
988}
989
Arend van Spriel5b435de2011-10-05 13:19:03 +0200990static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700991brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200992{
Johannes Bergfd014282012-06-18 19:17:03 +0200993 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200994 s32 err = 0;
995
Arend van Sprield96b8012012-12-05 15:26:02 +0100996 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200997
Arend van Sprielce81e312012-10-22 13:55:37 -0700998 if (!check_vif_up(container_of(request->wdev,
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700999 struct brcmf_cfg80211_vif, wdev)))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001000 return -EIO;
1001
Hante Meulemanf07998952012-11-05 16:22:13 -08001002 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +02001003
Arend van Spriel5b435de2011-10-05 13:19:03 +02001004 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001005 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001006
Arend van Sprield96b8012012-12-05 15:26:02 +01001007 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001008 return err;
1009}
1010
1011static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1012{
1013 s32 err = 0;
1014
Arend van Sprielac24be62012-10-22 10:36:23 -07001015 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1016 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001017 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001018 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001019
1020 return err;
1021}
1022
1023static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1024{
1025 s32 err = 0;
1026
Arend van Sprielac24be62012-10-22 10:36:23 -07001027 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1028 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001029 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001030 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001031
1032 return err;
1033}
1034
1035static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1036{
1037 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001038 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001039
Arend van Sprielac24be62012-10-22 10:36:23 -07001040 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001041 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001042 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001043 return err;
1044 }
1045 return err;
1046}
1047
1048static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1049{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001050 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1051 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001052 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001053 s32 err = 0;
1054
Arend van Sprield96b8012012-12-05 15:26:02 +01001055 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001056 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001057 return -EIO;
1058
1059 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001060 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1061 cfg->conf->rts_threshold = wiphy->rts_threshold;
1062 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001063 if (!err)
1064 goto done;
1065 }
1066 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001067 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1068 cfg->conf->frag_threshold = wiphy->frag_threshold;
1069 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001070 if (!err)
1071 goto done;
1072 }
1073 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001074 && (cfg->conf->retry_long != wiphy->retry_long)) {
1075 cfg->conf->retry_long = wiphy->retry_long;
1076 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001077 if (!err)
1078 goto done;
1079 }
1080 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001081 && (cfg->conf->retry_short != wiphy->retry_short)) {
1082 cfg->conf->retry_short = wiphy->retry_short;
1083 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001084 if (!err)
1085 goto done;
1086 }
1087
1088done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001089 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001090 return err;
1091}
1092
Arend van Spriel5b435de2011-10-05 13:19:03 +02001093static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1094{
1095 memset(prof, 0, sizeof(*prof));
1096}
1097
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001098static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001099{
Arend van Spriel5b435de2011-10-05 13:19:03 +02001100 s32 err = 0;
1101
Arend van Sprield96b8012012-12-05 15:26:02 +01001102 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001103
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001104 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001105 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001106 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001107 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001108 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001109 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001110 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001111 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001112 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001113 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001114}
1115
1116static s32
1117brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1118 struct cfg80211_ibss_params *params)
1119{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001120 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001121 struct brcmf_if *ifp = netdev_priv(ndev);
1122 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001123 struct brcmf_join_params join_params;
1124 size_t join_params_size = 0;
1125 s32 err = 0;
1126 s32 wsec = 0;
1127 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001128 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001129
Arend van Sprield96b8012012-12-05 15:26:02 +01001130 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001131 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001132 return -EIO;
1133
1134 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001135 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001136 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001137 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001138 return -EOPNOTSUPP;
1139 }
1140
Arend van Sprielc1179032012-10-22 13:55:33 -07001141 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001142
1143 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001144 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001145 else
Arend van Spriel16886732012-12-05 15:26:04 +01001146 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001147
Johannes Berg683b6d32012-11-08 21:25:48 +01001148 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001149 brcmf_dbg(CONN, "channel: %d\n",
1150 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001151 else
Arend van Spriel16886732012-12-05 15:26:04 +01001152 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001153
1154 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001155 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001156 else
Arend van Spriel16886732012-12-05 15:26:04 +01001157 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001158
1159 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001160 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001161 else
Arend van Spriel16886732012-12-05 15:26:04 +01001162 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001163
1164 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001165 brcmf_dbg(CONN, "beacon interval: %d\n",
1166 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001167 else
Arend van Spriel16886732012-12-05 15:26:04 +01001168 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001169
1170 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001171 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001172 else
Arend van Spriel16886732012-12-05 15:26:04 +01001173 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001174
1175 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001176 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001177 else
Arend van Spriel16886732012-12-05 15:26:04 +01001178 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001179
1180 /* Configure Privacy for starter */
1181 if (params->privacy)
1182 wsec |= WEP_ENABLED;
1183
Arend van Sprielc1179032012-10-22 13:55:33 -07001184 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001185 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001186 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001187 goto done;
1188 }
1189
1190 /* Configure Beacon Interval for starter */
1191 if (params->beacon_interval)
1192 bcnprd = params->beacon_interval;
1193 else
1194 bcnprd = 100;
1195
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001196 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001197 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001198 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 goto done;
1200 }
1201
1202 /* Configure required join parameter */
1203 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1204
1205 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001206 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1207 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1208 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1209 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001210 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001211
1212 /* BSSID */
1213 if (params->bssid) {
1214 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1215 join_params_size = sizeof(join_params.ssid_le) +
1216 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001217 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001218 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001219 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001220 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001221 }
1222
Arend van Spriel5b435de2011-10-05 13:19:03 +02001223 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001224 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001225 u32 target_channel;
1226
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001227 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001228 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001229 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001230 if (params->channel_fixed) {
1231 /* adding chanspec */
Hante Meuleman17012612013-02-06 18:40:44 +01001232 chanspec = channel_to_chanspec(params->chandef.chan);
1233 join_params.params_le.chanspec_list[0] =
1234 cpu_to_le16(chanspec);
1235 join_params.params_le.chanspec_num = cpu_to_le32(1);
1236 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001237 }
1238
1239 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001240 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001241 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001242 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001243 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001244 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001245 goto done;
1246 }
1247 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001248 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001249
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001250 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001251
1252
Arend van Sprielc1179032012-10-22 13:55:33 -07001253 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001254 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001255 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001256 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001257 goto done;
1258 }
1259
1260done:
1261 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001262 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001263 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001264 return err;
1265}
1266
1267static s32
1268brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1269{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001270 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001271 s32 err = 0;
1272
Arend van Sprield96b8012012-12-05 15:26:02 +01001273 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001274 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275 return -EIO;
1276
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001277 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001278
Arend van Sprield96b8012012-12-05 15:26:02 +01001279 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001280
1281 return err;
1282}
1283
1284static s32 brcmf_set_wpa_version(struct net_device *ndev,
1285 struct cfg80211_connect_params *sme)
1286{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001287 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001288 struct brcmf_cfg80211_security *sec;
1289 s32 val = 0;
1290 s32 err = 0;
1291
1292 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1293 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1294 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1295 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1296 else
1297 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001298 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001299 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001300 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001301 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001302 return err;
1303 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001304 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 sec->wpa_versions = sme->crypto.wpa_versions;
1306 return err;
1307}
1308
1309static s32 brcmf_set_auth_type(struct net_device *ndev,
1310 struct cfg80211_connect_params *sme)
1311{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001312 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001313 struct brcmf_cfg80211_security *sec;
1314 s32 val = 0;
1315 s32 err = 0;
1316
1317 switch (sme->auth_type) {
1318 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1319 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001320 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001321 break;
1322 case NL80211_AUTHTYPE_SHARED_KEY:
1323 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001324 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001325 break;
1326 case NL80211_AUTHTYPE_AUTOMATIC:
1327 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001328 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001329 break;
1330 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001331 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001332 default:
1333 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001334 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001335 break;
1336 }
1337
Hante Meuleman89286dc2013-02-08 15:53:46 +01001338 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001339 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001340 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001341 return err;
1342 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001343 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001344 sec->auth_type = sme->auth_type;
1345 return err;
1346}
1347
1348static s32
1349brcmf_set_set_cipher(struct net_device *ndev,
1350 struct cfg80211_connect_params *sme)
1351{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001352 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353 struct brcmf_cfg80211_security *sec;
1354 s32 pval = 0;
1355 s32 gval = 0;
1356 s32 err = 0;
1357
1358 if (sme->crypto.n_ciphers_pairwise) {
1359 switch (sme->crypto.ciphers_pairwise[0]) {
1360 case WLAN_CIPHER_SUITE_WEP40:
1361 case WLAN_CIPHER_SUITE_WEP104:
1362 pval = WEP_ENABLED;
1363 break;
1364 case WLAN_CIPHER_SUITE_TKIP:
1365 pval = TKIP_ENABLED;
1366 break;
1367 case WLAN_CIPHER_SUITE_CCMP:
1368 pval = AES_ENABLED;
1369 break;
1370 case WLAN_CIPHER_SUITE_AES_CMAC:
1371 pval = AES_ENABLED;
1372 break;
1373 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001374 brcmf_err("invalid cipher pairwise (%d)\n",
1375 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001376 return -EINVAL;
1377 }
1378 }
1379 if (sme->crypto.cipher_group) {
1380 switch (sme->crypto.cipher_group) {
1381 case WLAN_CIPHER_SUITE_WEP40:
1382 case WLAN_CIPHER_SUITE_WEP104:
1383 gval = WEP_ENABLED;
1384 break;
1385 case WLAN_CIPHER_SUITE_TKIP:
1386 gval = TKIP_ENABLED;
1387 break;
1388 case WLAN_CIPHER_SUITE_CCMP:
1389 gval = AES_ENABLED;
1390 break;
1391 case WLAN_CIPHER_SUITE_AES_CMAC:
1392 gval = AES_ENABLED;
1393 break;
1394 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001395 brcmf_err("invalid cipher group (%d)\n",
1396 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001397 return -EINVAL;
1398 }
1399 }
1400
Arend van Spriel16886732012-12-05 15:26:04 +01001401 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001402 /* In case of privacy, but no security and WPS then simulate */
1403 /* setting AES. WPS-2.0 allows no security */
1404 if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
1405 sme->privacy)
1406 pval = AES_ENABLED;
1407 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001409 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001410 return err;
1411 }
1412
Arend van Spriel06bb1232012-09-27 14:17:56 +02001413 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001414 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1415 sec->cipher_group = sme->crypto.cipher_group;
1416
1417 return err;
1418}
1419
1420static s32
1421brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1422{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001423 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001424 struct brcmf_cfg80211_security *sec;
1425 s32 val = 0;
1426 s32 err = 0;
1427
1428 if (sme->crypto.n_akm_suites) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01001429 err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
1430 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001431 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001432 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433 return err;
1434 }
1435 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1436 switch (sme->crypto.akm_suites[0]) {
1437 case WLAN_AKM_SUITE_8021X:
1438 val = WPA_AUTH_UNSPECIFIED;
1439 break;
1440 case WLAN_AKM_SUITE_PSK:
1441 val = WPA_AUTH_PSK;
1442 break;
1443 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001444 brcmf_err("invalid cipher group (%d)\n",
1445 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001446 return -EINVAL;
1447 }
1448 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1449 switch (sme->crypto.akm_suites[0]) {
1450 case WLAN_AKM_SUITE_8021X:
1451 val = WPA2_AUTH_UNSPECIFIED;
1452 break;
1453 case WLAN_AKM_SUITE_PSK:
1454 val = WPA2_AUTH_PSK;
1455 break;
1456 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001457 brcmf_err("invalid cipher group (%d)\n",
1458 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001459 return -EINVAL;
1460 }
1461 }
1462
Arend van Spriel16886732012-12-05 15:26:04 +01001463 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Hante Meuleman89286dc2013-02-08 15:53:46 +01001464 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
1465 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001467 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001468 return err;
1469 }
1470 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001471 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001472 sec->wpa_auth = sme->crypto.akm_suites[0];
1473
1474 return err;
1475}
1476
1477static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001478brcmf_set_sharedkey(struct net_device *ndev,
1479 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001481 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 struct brcmf_cfg80211_security *sec;
1483 struct brcmf_wsec_key key;
1484 s32 val;
1485 s32 err = 0;
1486
Arend van Spriel16886732012-12-05 15:26:04 +01001487 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001488
Roland Vossena718e2f2011-10-12 20:51:24 +02001489 if (sme->key_len == 0)
1490 return 0;
1491
Arend van Spriel06bb1232012-09-27 14:17:56 +02001492 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001493 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1494 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001495
1496 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1497 return 0;
1498
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001499 if (!(sec->cipher_pairwise &
1500 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1501 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001502
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001503 memset(&key, 0, sizeof(key));
1504 key.len = (u32) sme->key_len;
1505 key.index = (u32) sme->key_idx;
1506 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001507 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001508 return -EINVAL;
1509 }
1510 memcpy(key.data, sme->key, key.len);
1511 key.flags = BRCMF_PRIMARY_KEY;
1512 switch (sec->cipher_pairwise) {
1513 case WLAN_CIPHER_SUITE_WEP40:
1514 key.algo = CRYPTO_ALGO_WEP1;
1515 break;
1516 case WLAN_CIPHER_SUITE_WEP104:
1517 key.algo = CRYPTO_ALGO_WEP128;
1518 break;
1519 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001520 brcmf_err("Invalid algorithm (%d)\n",
1521 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001522 return -EINVAL;
1523 }
1524 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001525 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1526 key.len, key.index, key.algo);
1527 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001528 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001529 if (err)
1530 return err;
1531
1532 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001533 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001534 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001535 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001536 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001537 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538 }
1539 return err;
1540}
1541
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001542static
1543enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1544 enum nl80211_auth_type type)
1545{
1546 u32 ci;
1547 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1548 /* shift to ignore chip revision */
1549 ci = brcmf_get_chip_info(ifp) >> 4;
1550 switch (ci) {
1551 case 43236:
1552 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1553 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1554 default:
1555 break;
1556 }
1557 }
1558 return type;
1559}
1560
Arend van Spriel5b435de2011-10-05 13:19:03 +02001561static s32
1562brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001563 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001564{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001565 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001566 struct brcmf_if *ifp = netdev_priv(ndev);
1567 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001568 struct ieee80211_channel *chan = sme->channel;
1569 struct brcmf_join_params join_params;
1570 size_t join_params_size;
Hante Meuleman89286dc2013-02-08 15:53:46 +01001571 struct brcmf_tlv *rsn_ie;
1572 struct brcmf_vs_tlv *wpa_ie;
1573 void *ie;
1574 u32 ie_len;
1575 struct brcmf_ext_join_params_le *ext_join_params;
Hante Meuleman17012612013-02-06 18:40:44 +01001576 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001577
1578 s32 err = 0;
1579
Arend van Sprield96b8012012-12-05 15:26:02 +01001580 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001581 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 return -EIO;
1583
1584 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001585 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001586 return -EOPNOTSUPP;
1587 }
1588
Hante Meuleman89286dc2013-02-08 15:53:46 +01001589 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
1590 /* A normal (non P2P) connection request setup. */
1591 ie = NULL;
1592 ie_len = 0;
1593 /* find the WPA_IE */
1594 wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
1595 if (wpa_ie) {
1596 ie = wpa_ie;
1597 ie_len = wpa_ie->len + TLV_HDR_LEN;
1598 } else {
1599 /* find the RSN_IE */
1600 rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
1601 WLAN_EID_RSN);
1602 if (rsn_ie) {
1603 ie = rsn_ie;
1604 ie_len = rsn_ie->len + TLV_HDR_LEN;
1605 }
1606 }
1607 brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
1608 }
1609
1610 err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
1611 sme->ie, sme->ie_len);
1612 if (err)
1613 brcmf_err("Set Assoc REQ IE Failed\n");
1614 else
1615 brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
1616
Arend van Sprielc1179032012-10-22 13:55:33 -07001617 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001618
1619 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001620 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001621 ieee80211_frequency_to_channel(chan->center_freq);
Hante Meuleman17012612013-02-06 18:40:44 +01001622 chanspec = channel_to_chanspec(chan);
1623 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1624 cfg->channel, chan->center_freq, chanspec);
1625 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001626 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001627 chanspec = 0;
1628 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001629
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001630 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001631
1632 err = brcmf_set_wpa_version(ndev, sme);
1633 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001634 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001635 goto done;
1636 }
1637
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001638 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001639 err = brcmf_set_auth_type(ndev, sme);
1640 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001641 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001642 goto done;
1643 }
1644
1645 err = brcmf_set_set_cipher(ndev, sme);
1646 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001647 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001648 goto done;
1649 }
1650
1651 err = brcmf_set_key_mgmt(ndev, sme);
1652 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001653 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001654 goto done;
1655 }
1656
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001657 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001658 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001659 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001660 goto done;
1661 }
1662
Hante Meuleman89286dc2013-02-08 15:53:46 +01001663 profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
1664 (u32)sme->ssid_len);
1665 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1666 if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1667 profile->ssid.SSID[profile->ssid.SSID_len] = 0;
1668 brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
1669 profile->ssid.SSID_len);
1670 }
1671
1672 /* Join with specific BSSID and cached SSID
1673 * If SSID is zero join based on BSSID only
1674 */
1675 join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
1676 offsetof(struct brcmf_assoc_params_le, chanspec_list);
1677 if (cfg->channel)
1678 join_params_size += sizeof(u16);
1679 ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
1680 if (ext_join_params == NULL) {
1681 err = -ENOMEM;
1682 goto done;
1683 }
1684 ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1685 memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
1686 profile->ssid.SSID_len);
1687 /*increase dwell time to receive probe response or detect Beacon
1688 * from target AP at a noisy air only during connect command
1689 */
1690 ext_join_params->scan_le.active_time =
1691 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
1692 ext_join_params->scan_le.passive_time =
1693 cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
1694 /* Set up join scan parameters */
1695 ext_join_params->scan_le.scan_type = -1;
1696 /* to sync with presence period of VSDB GO.
1697 * Send probe request more frequently. Probe request will be stopped
1698 * when it gets probe response from target AP/GO.
1699 */
1700 ext_join_params->scan_le.nprobes =
1701 cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
1702 BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
1703 ext_join_params->scan_le.home_time = cpu_to_le32(-1);
1704
1705 if (sme->bssid)
1706 memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
1707 else
1708 memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
1709
1710 if (cfg->channel) {
1711 ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
1712
1713 ext_join_params->assoc_le.chanspec_list[0] =
1714 cpu_to_le16(chanspec);
1715 }
1716
1717 err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
1718 join_params_size);
1719 kfree(ext_join_params);
1720 if (!err)
1721 /* This is it. join command worked, we are done */
1722 goto done;
1723
1724 /* join command failed, fallback to set ssid */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001725 memset(&join_params, 0, sizeof(join_params));
1726 join_params_size = sizeof(join_params.ssid_le);
1727
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001728 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001729 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001730
Hante Meuleman89286dc2013-02-08 15:53:46 +01001731 if (sme->bssid)
1732 memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
1733 else
1734 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001735
Hante Meuleman17012612013-02-06 18:40:44 +01001736 if (cfg->channel) {
1737 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1738 join_params.params_le.chanspec_num = cpu_to_le32(1);
1739 join_params_size += sizeof(join_params.params_le);
1740 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001741 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001742 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001743 if (err)
Hante Meuleman89286dc2013-02-08 15:53:46 +01001744 brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001745
1746done:
1747 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001748 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001749 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001750 return err;
1751}
1752
1753static s32
1754brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1755 u16 reason_code)
1756{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001757 struct brcmf_if *ifp = netdev_priv(ndev);
1758 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001759 struct brcmf_scb_val_le scbval;
1760 s32 err = 0;
1761
Arend van Sprield96b8012012-12-05 15:26:02 +01001762 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001763 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001764 return -EIO;
1765
Arend van Sprielc1179032012-10-22 13:55:33 -07001766 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001767
Arend van Spriel06bb1232012-09-27 14:17:56 +02001768 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001769 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001770 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001771 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001772 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001773 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001774
Arend van Sprield96b8012012-12-05 15:26:02 +01001775 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001776 return err;
1777}
1778
1779static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001780brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001781 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001782{
1783
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001784 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001785 struct net_device *ndev = cfg_to_ndev(cfg);
1786 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001787 u16 txpwrmw;
1788 s32 err = 0;
1789 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001790 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001791
Arend van Sprield96b8012012-12-05 15:26:02 +01001792 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001793 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001794 return -EIO;
1795
1796 switch (type) {
1797 case NL80211_TX_POWER_AUTOMATIC:
1798 break;
1799 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001800 case NL80211_TX_POWER_FIXED:
1801 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001802 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001803 err = -EINVAL;
1804 goto done;
1805 }
1806 break;
1807 }
1808 /* Make sure radio is off or on as far as software is concerned */
1809 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001810 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001811 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001812 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001813
1814 if (dbm > 0xffff)
1815 txpwrmw = 0xffff;
1816 else
1817 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001818 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1819 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001820 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001821 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001822 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001823
1824done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001825 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001826 return err;
1827}
1828
Johannes Bergc8442112012-10-24 10:17:18 +02001829static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1830 struct wireless_dev *wdev,
1831 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001832{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001833 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001834 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001835 s32 txpwrdbm;
1836 u8 result;
1837 s32 err = 0;
1838
Arend van Sprield96b8012012-12-05 15:26:02 +01001839 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001840 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001841 return -EIO;
1842
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001843 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001844 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001845 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001846 goto done;
1847 }
1848
1849 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001850 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001851
1852done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001853 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001854 return err;
1855}
1856
1857static s32
1858brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1859 u8 key_idx, bool unicast, bool multicast)
1860{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001861 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001862 u32 index;
1863 u32 wsec;
1864 s32 err = 0;
1865
Arend van Sprield96b8012012-12-05 15:26:02 +01001866 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001867 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001868 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001869 return -EIO;
1870
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001871 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001872 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001873 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001874 goto done;
1875 }
1876
1877 if (wsec & WEP_ENABLED) {
1878 /* Just select a new current key */
1879 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001880 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001881 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001882 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001883 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001884 }
1885done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001886 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001887 return err;
1888}
1889
1890static s32
1891brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1892 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1893{
1894 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001895 s32 err = 0;
1896
1897 memset(&key, 0, sizeof(key));
1898 key.index = (u32) key_idx;
1899 /* Instead of bcast for ea address for default wep keys,
1900 driver needs it to be Null */
1901 if (!is_multicast_ether_addr(mac_addr))
1902 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1903 key.len = (u32) params->key_len;
1904 /* check for key index change */
1905 if (key.len == 0) {
1906 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001907 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001908 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001909 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910 } else {
1911 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001912 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001913 return -EINVAL;
1914 }
1915
Arend van Spriel16886732012-12-05 15:26:04 +01001916 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917 memcpy(key.data, params->key, key.len);
1918
1919 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1920 u8 keybuf[8];
1921 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1922 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1923 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1924 }
1925
1926 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1927 if (params->seq && params->seq_len == 6) {
1928 /* rx iv */
1929 u8 *ivptr;
1930 ivptr = (u8 *) params->seq;
1931 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1932 (ivptr[3] << 8) | ivptr[2];
1933 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1934 key.iv_initialized = true;
1935 }
1936
1937 switch (params->cipher) {
1938 case WLAN_CIPHER_SUITE_WEP40:
1939 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001940 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001941 break;
1942 case WLAN_CIPHER_SUITE_WEP104:
1943 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001944 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001945 break;
1946 case WLAN_CIPHER_SUITE_TKIP:
1947 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001948 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001949 break;
1950 case WLAN_CIPHER_SUITE_AES_CMAC:
1951 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001952 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001953 break;
1954 case WLAN_CIPHER_SUITE_CCMP:
1955 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001956 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001957 break;
1958 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001959 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001960 return -EINVAL;
1961 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001962 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001963 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001964 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001965 }
1966 return err;
1967}
1968
1969static s32
1970brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1971 u8 key_idx, bool pairwise, const u8 *mac_addr,
1972 struct key_params *params)
1973{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001974 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001975 struct brcmf_wsec_key key;
1976 s32 val;
1977 s32 wsec;
1978 s32 err = 0;
1979 u8 keybuf[8];
1980
Arend van Sprield96b8012012-12-05 15:26:02 +01001981 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001982 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001983 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001984 return -EIO;
1985
1986 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001987 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001988 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1989 }
1990 memset(&key, 0, sizeof(key));
1991
1992 key.len = (u32) params->key_len;
1993 key.index = (u32) key_idx;
1994
1995 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001996 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001997 err = -EINVAL;
1998 goto done;
1999 }
2000 memcpy(key.data, params->key, key.len);
2001
2002 key.flags = BRCMF_PRIMARY_KEY;
2003 switch (params->cipher) {
2004 case WLAN_CIPHER_SUITE_WEP40:
2005 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002006 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002007 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002008 break;
2009 case WLAN_CIPHER_SUITE_WEP104:
2010 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002011 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002012 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002013 break;
2014 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002015 if (ifp->vif->mode != WL_MODE_AP) {
Arend van Spriel16886732012-12-05 15:26:04 +01002016 brcmf_dbg(CONN, "Swapping key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02002017 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2018 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2019 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2020 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002021 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002022 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002023 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002024 break;
2025 case WLAN_CIPHER_SUITE_AES_CMAC:
2026 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002027 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002028 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002029 break;
2030 case WLAN_CIPHER_SUITE_CCMP:
2031 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002032 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01002033 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002034 break;
2035 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002036 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002037 err = -EINVAL;
2038 goto done;
2039 }
2040
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002041 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002042 if (err)
2043 goto done;
2044
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002045 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002046 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002047 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 goto done;
2049 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002051 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002052 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002053 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054 goto done;
2055 }
2056
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002058 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002059 return err;
2060}
2061
2062static s32
2063brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2064 u8 key_idx, bool pairwise, const u8 *mac_addr)
2065{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002066 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002067 struct brcmf_wsec_key key;
2068 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069
Arend van Sprield96b8012012-12-05 15:26:02 +01002070 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002071 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072 return -EIO;
2073
Hante Meuleman256c3742012-11-05 16:22:28 -08002074 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
2075 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01002076 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08002077 return -EINVAL;
2078 }
2079
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 memset(&key, 0, sizeof(key));
2081
2082 key.index = (u32) key_idx;
2083 key.flags = BRCMF_PRIMARY_KEY;
2084 key.algo = CRYPTO_ALGO_OFF;
2085
Arend van Spriel16886732012-12-05 15:26:04 +01002086 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002087
2088 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002089 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002090
Arend van Sprield96b8012012-12-05 15:26:02 +01002091 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002092 return err;
2093}
2094
2095static s32
2096brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2097 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2098 void (*callback) (void *cookie, struct key_params * params))
2099{
2100 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002101 struct brcmf_if *ifp = netdev_priv(ndev);
2102 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002103 struct brcmf_cfg80211_security *sec;
2104 s32 wsec;
2105 s32 err = 0;
2106
Arend van Sprield96b8012012-12-05 15:26:02 +01002107 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01002108 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002109 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002110 return -EIO;
2111
2112 memset(&params, 0, sizeof(params));
2113
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002114 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002115 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002116 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002117 /* Ignore this error, may happen during DISASSOC */
2118 err = -EAGAIN;
2119 goto done;
2120 }
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002121 switch (wsec & ~SES_OW_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002122 case WEP_ENABLED:
Arend van Spriel06bb1232012-09-27 14:17:56 +02002123 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002124 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2125 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01002126 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002127 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2128 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01002129 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002130 }
2131 break;
2132 case TKIP_ENABLED:
2133 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01002134 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135 break;
2136 case AES_ENABLED:
2137 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01002138 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002139 break;
2140 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01002141 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002142 err = -EINVAL;
2143 goto done;
2144 }
2145 callback(cookie, &params);
2146
2147done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002148 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 return err;
2150}
2151
2152static s32
2153brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2154 struct net_device *ndev, u8 key_idx)
2155{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002156 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002157
2158 return -EOPNOTSUPP;
2159}
2160
2161static s32
2162brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002163 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002165 struct brcmf_if *ifp = netdev_priv(ndev);
2166 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 struct brcmf_scb_val_le scb_val;
2168 int rssi;
2169 s32 rate;
2170 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002171 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002172 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002173
Arend van Sprield96b8012012-12-05 15:26:02 +01002174 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002175 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002176 return -EIO;
2177
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002178 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002179 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002180 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002181 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002182 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002183 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002184 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002185 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002186 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002187 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002188 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2189 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002190 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002191 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002192 }
Arend van Sprield96b8012012-12-05 15:26:02 +01002193 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
2194 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002195 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002196 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002197 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2198 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02002199 err = -ENOENT;
2200 goto done;
2201 }
2202 /* Report the current tx rate */
Hante Meuleman89286dc2013-02-08 15:53:46 +01002203 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002204 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002205 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002206 goto done;
2207 } else {
2208 sinfo->filled |= STATION_INFO_TX_BITRATE;
2209 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002210 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002211 }
2212
Arend van Sprielc1179032012-10-22 13:55:33 -07002213 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2214 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002215 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002216 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2217 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002218 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002219 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002220 goto done;
2221 } else {
2222 rssi = le32_to_cpu(scb_val.val);
2223 sinfo->filled |= STATION_INFO_SIGNAL;
2224 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002225 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002226 }
2227 }
2228 } else
2229 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002230done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002231 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002232 return err;
2233}
2234
2235static s32
2236brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2237 bool enabled, s32 timeout)
2238{
2239 s32 pm;
2240 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002241 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002242 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002243
Arend van Sprield96b8012012-12-05 15:26:02 +01002244 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002245
2246 /*
2247 * Powersave enable/disable request is coming from the
2248 * cfg80211 even before the interface is up. In that
2249 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002250 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002251 * FW later while initializing the dongle
2252 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002253 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002254 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002255
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002256 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002257 goto done;
2258 }
2259
2260 pm = enabled ? PM_FAST : PM_OFF;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002261 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002262
Arend van Sprielc1179032012-10-22 13:55:33 -07002263 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002264 if (err) {
2265 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002266 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002268 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002269 }
2270done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002271 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002272 return err;
2273}
2274
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002275static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002276 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002278 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002279 struct ieee80211_channel *notify_channel;
2280 struct cfg80211_bss *bss;
2281 struct ieee80211_supported_band *band;
2282 s32 err = 0;
2283 u16 channel;
2284 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002285 u16 notify_capability;
2286 u16 notify_interval;
2287 u8 *notify_ie;
2288 size_t notify_ielen;
2289 s32 notify_signal;
2290
2291 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002292 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002293 return 0;
2294 }
2295
2296 channel = bi->ctl_ch ? bi->ctl_ch :
2297 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2298
2299 if (channel <= CH_MAX_2G_CHANNEL)
2300 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2301 else
2302 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2303
2304 freq = ieee80211_channel_to_frequency(channel, band->band);
2305 notify_channel = ieee80211_get_channel(wiphy, freq);
2306
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307 notify_capability = le16_to_cpu(bi->capability);
2308 notify_interval = le16_to_cpu(bi->beacon_period);
2309 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2310 notify_ielen = le32_to_cpu(bi->ie_length);
2311 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2312
Arend van Spriel16886732012-12-05 15:26:04 +01002313 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2314 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2315 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2316 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2317 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002318
2319 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002320 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002321 notify_ielen, notify_signal, GFP_KERNEL);
2322
Franky Line78946e2011-11-10 20:30:34 +01002323 if (!bss)
2324 return -ENOMEM;
2325
Johannes Berg5b112d32013-02-01 01:49:58 +01002326 cfg80211_put_bss(wiphy, bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002327
2328 return err;
2329}
2330
Roland Vossen6f09be02011-10-18 14:03:02 +02002331static struct brcmf_bss_info_le *
2332next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2333{
2334 if (bss == NULL)
2335 return list->bss_info_le;
2336 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2337 le32_to_cpu(bss->length));
2338}
2339
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002340static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002341{
2342 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002343 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344 s32 err = 0;
2345 int i;
2346
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002347 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002348 if (bss_list->count != 0 &&
2349 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002350 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2351 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002352 return -EOPNOTSUPP;
2353 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002354 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002355 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002356 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002357 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002358 if (err)
2359 break;
2360 }
2361 return err;
2362}
2363
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002364static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365 struct net_device *ndev, const u8 *bssid)
2366{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002367 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002368 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002369 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002370 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002371 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002372 u8 *buf = NULL;
2373 s32 err = 0;
2374 u16 channel;
2375 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376 u16 notify_capability;
2377 u16 notify_interval;
2378 u8 *notify_ie;
2379 size_t notify_ielen;
2380 s32 notify_signal;
2381
Arend van Sprield96b8012012-12-05 15:26:02 +01002382 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002383
2384 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2385 if (buf == NULL) {
2386 err = -ENOMEM;
2387 goto CleanUp;
2388 }
2389
2390 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2391
Arend van Sprielac24be62012-10-22 10:36:23 -07002392 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2393 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002394 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002395 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002396 goto CleanUp;
2397 }
2398
Roland Vossend34bf642011-10-18 14:03:01 +02002399 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002400
2401 channel = bi->ctl_ch ? bi->ctl_ch :
2402 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2403
2404 if (channel <= CH_MAX_2G_CHANNEL)
2405 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2406 else
2407 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2408
2409 freq = ieee80211_channel_to_frequency(channel, band->band);
2410 notify_channel = ieee80211_get_channel(wiphy, freq);
2411
Arend van Spriel5b435de2011-10-05 13:19:03 +02002412 notify_capability = le16_to_cpu(bi->capability);
2413 notify_interval = le16_to_cpu(bi->beacon_period);
2414 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2415 notify_ielen = le32_to_cpu(bi->ie_length);
2416 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2417
Arend van Spriel16886732012-12-05 15:26:04 +01002418 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2419 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2420 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2421 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002422
Franky Line78946e2011-11-10 20:30:34 +01002423 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002424 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2426
Franky Line78946e2011-11-10 20:30:34 +01002427 if (!bss) {
2428 err = -ENOMEM;
2429 goto CleanUp;
2430 }
2431
Johannes Berg5b112d32013-02-01 01:49:58 +01002432 cfg80211_put_bss(wiphy, bss);
Franky Line78946e2011-11-10 20:30:34 +01002433
Arend van Spriel5b435de2011-10-05 13:19:03 +02002434CleanUp:
2435
2436 kfree(buf);
2437
Arend van Sprield96b8012012-12-05 15:26:02 +01002438 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002439
2440 return err;
2441}
2442
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002443static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002444{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002445 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002446}
2447
Hante Meuleman89286dc2013-02-08 15:53:46 +01002448static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
2449 struct brcmf_if *ifp)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002450{
Hante Meuleman89286dc2013-02-08 15:53:46 +01002451 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002452 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002453 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002454 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002455 u16 beacon_interval;
2456 u8 dtim_period;
2457 size_t ie_len;
2458 u8 *ie;
2459 s32 err = 0;
2460
Arend van Sprield96b8012012-12-05 15:26:02 +01002461 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002462 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002463 return err;
2464
Arend van Spriel06bb1232012-09-27 14:17:56 +02002465 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002466
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002467 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002468 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002469 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002470 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002471 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002472 goto update_bss_info_out;
2473 }
2474
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002475 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2476 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002477 if (err)
2478 goto update_bss_info_out;
2479
2480 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2481 ie_len = le32_to_cpu(bi->ie_length);
2482 beacon_interval = le16_to_cpu(bi->beacon_period);
2483
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002484 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002485 if (tim)
2486 dtim_period = tim->data[1];
2487 else {
2488 /*
2489 * active scan was done so we could not get dtim
2490 * information out of probe response.
2491 * so we speficially query dtim information to dongle.
2492 */
2493 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002494 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002495 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002496 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002497 goto update_bss_info_out;
2498 }
2499 dtim_period = (u8)var;
2500 }
2501
Arend van Spriel5b435de2011-10-05 13:19:03 +02002502update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002503 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002504 return err;
2505}
2506
Hante Meuleman18e2f612013-02-08 15:53:49 +01002507void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002508{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002509 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002510
Arend van Sprielc1179032012-10-22 13:55:33 -07002511 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002512 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002513 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002514 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002515 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002516 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2517 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002518}
2519
Hante Meulemane756af52012-09-11 21:18:52 +02002520static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2521{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002522 struct brcmf_cfg80211_info *cfg =
2523 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002524 escan_timeout_work);
2525
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002526 brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002527}
2528
2529static void brcmf_escan_timeout(unsigned long data)
2530{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002531 struct brcmf_cfg80211_info *cfg =
2532 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002533
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002534 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002535 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002536 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002537 }
2538}
2539
2540static s32
2541brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2542 struct brcmf_bss_info_le *bss_info_le)
2543{
2544 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2545 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2546 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2547 bss_info_le->SSID_len == bss->SSID_len &&
2548 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2549 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2550 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002551 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2552 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2553
Hante Meulemane756af52012-09-11 21:18:52 +02002554 /* preserve max RSSI if the measurements are
2555 * both on-channel or both off-channel
2556 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002557 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002558 bss->RSSI = bss_info_le->RSSI;
2559 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2560 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2561 /* preserve the on-channel rssi measurement
2562 * if the new measurement is off channel
2563 */
2564 bss->RSSI = bss_info_le->RSSI;
2565 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2566 }
2567 return 1;
2568 }
2569 return 0;
2570}
2571
2572static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002573brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002574 const struct brcmf_event_msg *e, void *data)
2575{
Arend van Spriel19937322012-11-05 16:22:32 -08002576 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2577 struct net_device *ndev = ifp->ndev;
Hante Meulemane756af52012-09-11 21:18:52 +02002578 s32 status;
2579 s32 err = 0;
2580 struct brcmf_escan_result_le *escan_result_le;
2581 struct brcmf_bss_info_le *bss_info_le;
2582 struct brcmf_bss_info_le *bss = NULL;
2583 u32 bi_length;
2584 struct brcmf_scan_results *list;
2585 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002586 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002587
Arend van Spriel5c36b992012-11-14 18:46:05 -08002588 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002589
Hante Meulemanf07998952012-11-05 16:22:13 -08002590 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002591 brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
2592 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
Hante Meulemane756af52012-09-11 21:18:52 +02002593 return -EPERM;
2594 }
2595
2596 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002597 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002598 escan_result_le = (struct brcmf_escan_result_le *) data;
2599 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002600 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002601 goto exit;
2602 }
Hante Meulemane756af52012-09-11 21:18:52 +02002603 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002604 brcmf_err("Invalid bss_count %d: ignoring\n",
2605 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002606 goto exit;
2607 }
2608 bss_info_le = &escan_result_le->bss_info_le;
2609
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002610 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
2611 goto exit;
2612
2613 if (!cfg->scan_request) {
2614 brcmf_dbg(SCAN, "result without cfg80211 request\n");
2615 goto exit;
2616 }
2617
Hante Meulemane756af52012-09-11 21:18:52 +02002618 bi_length = le32_to_cpu(bss_info_le->length);
2619 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2620 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002621 brcmf_err("Invalid bss_info length %d: ignoring\n",
2622 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002623 goto exit;
2624 }
2625
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002626 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002627 BIT(NL80211_IFTYPE_ADHOC))) {
2628 if (le16_to_cpu(bss_info_le->capability) &
2629 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002630 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002631 goto exit;
2632 }
2633 }
2634
2635 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002636 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002637 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002638 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002639 goto exit;
2640 }
2641
2642 for (i = 0; i < list->count; i++) {
2643 bss = bss ? (struct brcmf_bss_info_le *)
2644 ((unsigned char *)bss +
2645 le32_to_cpu(bss->length)) : list->bss_info_le;
2646 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2647 goto exit;
2648 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002649 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002650 bss_info_le, bi_length);
2651 list->version = le32_to_cpu(bss_info_le->version);
2652 list->buflen += bi_length;
2653 list->count++;
2654 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002655 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002656 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
2657 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002658 if (cfg->scan_request) {
2659 cfg->bss_list = (struct brcmf_scan_results *)
2660 cfg->escan_info.escan_buf;
2661 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002662 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002663 brcmf_notify_escan_complete(cfg, ndev, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002664 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002665 } else
Hante Meuleman6eda4e22013-02-08 15:54:02 +01002666 brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
2667 status);
Hante Meulemane756af52012-09-11 21:18:52 +02002668 }
2669exit:
2670 return err;
2671}
2672
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002673static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002674{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002675 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2676 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002677 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2678 /* Init scan_timeout timer */
2679 init_timer(&cfg->escan_timeout);
2680 cfg->escan_timeout.data = (unsigned long) cfg;
2681 cfg->escan_timeout.function = brcmf_escan_timeout;
2682 INIT_WORK(&cfg->escan_timeout_work,
2683 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002684}
2685
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002686static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002687{
2688 if (ms < 1000 / HZ) {
2689 cond_resched();
2690 mdelay(ms);
2691 } else {
2692 msleep(ms);
2693 }
2694}
2695
2696static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2697{
Arend van Sprield96b8012012-12-05 15:26:02 +01002698 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002699
Arend van Spriel5b435de2011-10-05 13:19:03 +02002700 return 0;
2701}
2702
2703static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2704 struct cfg80211_wowlan *wow)
2705{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002706 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2707 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002708 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002709
Arend van Sprield96b8012012-12-05 15:26:02 +01002710 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002711
2712 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002713 * if the primary net_device is not READY there is nothing
2714 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002715 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002716 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2717 if (!check_vif_up(vif))
2718 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002719
Arend van Spriel7d641072012-10-22 13:55:39 -07002720 list_for_each_entry(vif, &cfg->vif_list, list) {
2721 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2722 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002723 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002724 * While going to suspend if associated with AP disassociate
2725 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002726 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002727 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002728
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002729 /* Make sure WPA_Supplicant receives all the event
2730 * generated due to DISASSOC call to the fw to keep
2731 * the state fw and WPA_Supplicant state consistent
2732 */
2733 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002734 }
2735
Arend van Spriel7d641072012-10-22 13:55:39 -07002736 /* end any scanning */
2737 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002738 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002739
2740 /* Turn off watchdog timer */
Arend van Spriel7d641072012-10-22 13:55:39 -07002741 brcmf_set_mpc(ndev, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002742
Arend van Spriel7d641072012-10-22 13:55:39 -07002743exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002744 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002745 /* clear any scanning activity */
2746 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002747 return 0;
2748}
2749
2750static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002751brcmf_update_pmklist(struct net_device *ndev,
2752 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2753{
2754 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002755 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002756
Arend van Spriel40c8e952011-10-12 20:51:20 +02002757 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2758
Arend van Spriel16886732012-12-05 15:26:04 +01002759 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002760 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002761 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2762 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002763 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002764 brcmf_dbg(CONN, "%02x\n",
2765 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002766 }
2767
2768 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002769 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2770 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002771
2772 return err;
2773}
2774
2775static s32
2776brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2777 struct cfg80211_pmksa *pmksa)
2778{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002779 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002780 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002781 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002782 s32 err = 0;
2783 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002784 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002785
Arend van Sprield96b8012012-12-05 15:26:02 +01002786 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002787 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002788 return -EIO;
2789
Arend van Spriel40c8e952011-10-12 20:51:20 +02002790 pmkid_len = le32_to_cpu(pmkids->npmkid);
2791 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002792 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2793 break;
2794 if (i < WL_NUM_PMKIDS_MAX) {
2795 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2796 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002797 if (i == pmkid_len) {
2798 pmkid_len++;
2799 pmkids->npmkid = cpu_to_le32(pmkid_len);
2800 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002801 } else
2802 err = -EINVAL;
2803
Arend van Spriel16886732012-12-05 15:26:04 +01002804 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2805 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002807 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002808
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002809 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002810
Arend van Sprield96b8012012-12-05 15:26:02 +01002811 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002812 return err;
2813}
2814
2815static s32
2816brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2817 struct cfg80211_pmksa *pmksa)
2818{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002819 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002820 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002821 struct pmkid_list pmkid;
2822 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002823 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002824
Arend van Sprield96b8012012-12-05 15:26:02 +01002825 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002826 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002827 return -EIO;
2828
2829 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2830 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2831
Arend van Spriel16886732012-12-05 15:26:04 +01002832 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2833 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002834 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002835 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002836
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002837 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002838 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002839 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002840 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002841 ETH_ALEN))
2842 break;
2843
Arend van Spriel40c8e952011-10-12 20:51:20 +02002844 if ((pmkid_len > 0)
2845 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002846 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002847 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002848 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002849 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2850 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002851 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002852 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2853 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002854 WLAN_PMKID_LEN);
2855 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002856 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002857 } else
2858 err = -EINVAL;
2859
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002860 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002861
Arend van Sprield96b8012012-12-05 15:26:02 +01002862 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002863 return err;
2864
2865}
2866
2867static s32
2868brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2869{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002870 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002871 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002872 s32 err = 0;
2873
Arend van Sprield96b8012012-12-05 15:26:02 +01002874 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002875 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002876 return -EIO;
2877
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002878 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2879 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002880
Arend van Sprield96b8012012-12-05 15:26:02 +01002881 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002882 return err;
2883
2884}
2885
Arend van Spriele5806072012-09-19 22:21:08 +02002886/*
2887 * PFN result doesn't have all the info which are
2888 * required by the supplicant
2889 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2890 * via wl_inform_single_bss in the required format. Escan does require the
2891 * scan request in the form of cfg80211_scan_request. For timebeing, create
2892 * cfg80211_scan_request one out of the received PNO event.
2893 */
2894static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002895brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002896 const struct brcmf_event_msg *e, void *data)
2897{
Arend van Spriel19937322012-11-05 16:22:32 -08002898 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2899 struct net_device *ndev = ifp->ndev;
Arend van Spriele5806072012-09-19 22:21:08 +02002900 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2901 struct cfg80211_scan_request *request = NULL;
2902 struct cfg80211_ssid *ssid = NULL;
2903 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002904 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002905 int err = 0;
2906 int channel_req = 0;
2907 int band = 0;
2908 struct brcmf_pno_scanresults_le *pfn_result;
2909 u32 result_count;
2910 u32 status;
2911
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002912 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002913
Arend van Spriel5c36b992012-11-14 18:46:05 -08002914 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002915 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002916 return 0;
2917 }
2918
2919 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2920 result_count = le32_to_cpu(pfn_result->count);
2921 status = le32_to_cpu(pfn_result->status);
2922
2923 /*
2924 * PFN event is limited to fit 512 bytes so we may get
2925 * multiple NET_FOUND events. For now place a warning here.
2926 */
2927 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002928 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002929 if (result_count > 0) {
2930 int i;
2931
2932 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002933 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2934 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002935 if (!request || !ssid || !channel) {
2936 err = -ENOMEM;
2937 goto out_err;
2938 }
2939
2940 request->wiphy = wiphy;
2941 data += sizeof(struct brcmf_pno_scanresults_le);
2942 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2943
2944 for (i = 0; i < result_count; i++) {
2945 netinfo = &netinfo_start[i];
2946 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002947 brcmf_err("Invalid netinfo ptr. index: %d\n",
2948 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002949 err = -EINVAL;
2950 goto out_err;
2951 }
2952
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002953 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2954 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002955 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2956 ssid[i].ssid_len = netinfo->SSID_len;
2957 request->n_ssids++;
2958
2959 channel_req = netinfo->channel;
2960 if (channel_req <= CH_MAX_2G_CHANNEL)
2961 band = NL80211_BAND_2GHZ;
2962 else
2963 band = NL80211_BAND_5GHZ;
2964 channel[i].center_freq =
2965 ieee80211_channel_to_frequency(channel_req,
2966 band);
2967 channel[i].band = band;
2968 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2969 request->channels[i] = &channel[i];
2970 request->n_channels++;
2971 }
2972
2973 /* assign parsed ssid array */
2974 if (request->n_ssids)
2975 request->ssids = &ssid[0];
2976
Arend van Sprielc1179032012-10-22 13:55:33 -07002977 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002978 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002979 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002980 }
2981
Arend van Sprielc1179032012-10-22 13:55:33 -07002982 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002983 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002984 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002985 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002986 goto out_err;
2987 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002988 cfg->sched_escan = true;
2989 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002990 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002991 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002992 goto out_err;
2993 }
2994
2995 kfree(ssid);
2996 kfree(channel);
2997 kfree(request);
2998 return 0;
2999
3000out_err:
3001 kfree(ssid);
3002 kfree(channel);
3003 kfree(request);
3004 cfg80211_sched_scan_stopped(wiphy);
3005 return err;
3006}
3007
Arend van Spriele5806072012-09-19 22:21:08 +02003008static int brcmf_dev_pno_clean(struct net_device *ndev)
3009{
Arend van Spriele5806072012-09-19 22:21:08 +02003010 int ret;
3011
3012 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003013 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003014 if (ret == 0) {
3015 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003016 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3017 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003018 }
3019 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003020 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003021
3022 return ret;
3023}
3024
3025static int brcmf_dev_pno_config(struct net_device *ndev)
3026{
3027 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003028
3029 memset(&pfn_param, 0, sizeof(pfn_param));
3030 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3031
3032 /* set extra pno params */
3033 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3034 pfn_param.repeat = BRCMF_PNO_REPEAT;
3035 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3036
3037 /* set up pno scan fr */
3038 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3039
Arend van Sprielac24be62012-10-22 10:36:23 -07003040 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3041 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003042}
3043
3044static int
3045brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3046 struct net_device *ndev,
3047 struct cfg80211_sched_scan_request *request)
3048{
Arend van Sprielc1179032012-10-22 13:55:33 -07003049 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003050 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003051 struct brcmf_pno_net_param_le pfn;
3052 int i;
3053 int ret = 0;
3054
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003055 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3056 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003057 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003058 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003059 return -EAGAIN;
3060 }
3061
3062 if (!request || !request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003063 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
3064 request ? request->n_ssids : 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003065 return -EINVAL;
3066 }
3067
3068 if (request->n_ssids > 0) {
3069 for (i = 0; i < request->n_ssids; i++) {
3070 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003071 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
3072 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003073
3074 /*
3075 * match_set ssids is a supert set of n_ssid list,
3076 * so we need not add these set seperately.
3077 */
3078 }
3079 }
3080
3081 if (request->n_match_sets > 0) {
3082 /* clean up everything */
3083 ret = brcmf_dev_pno_clean(ndev);
3084 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003085 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003086 return ret;
3087 }
3088
3089 /* configure pno */
3090 ret = brcmf_dev_pno_config(ndev);
3091 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003092 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003093 return -EINVAL;
3094 }
3095
3096 /* configure each match set */
3097 for (i = 0; i < request->n_match_sets; i++) {
3098 struct cfg80211_ssid *ssid;
3099 u32 ssid_len;
3100
3101 ssid = &request->match_sets[i].ssid;
3102 ssid_len = ssid->ssid_len;
3103
3104 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003105 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003106 continue;
3107 }
3108 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3109 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3110 pfn.wsec = cpu_to_le32(0);
3111 pfn.infra = cpu_to_le32(1);
3112 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3113 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3114 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003115 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003116 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003117 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
3118 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02003119 }
3120 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003121 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003122 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02003123 return -EINVAL;
3124 }
3125 } else {
3126 return -EINVAL;
3127 }
3128
3129 return 0;
3130}
3131
3132static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3133 struct net_device *ndev)
3134{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003135 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003136
Arend van Spriel4e8a0082012-12-05 15:26:03 +01003137 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02003138 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003139 if (cfg->sched_escan)
3140 brcmf_notify_escan_complete(cfg, ndev, true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003141 return 0;
3142}
Arend van Spriele5806072012-09-19 22:21:08 +02003143
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003144#ifdef CONFIG_NL80211_TESTMODE
3145static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3146{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003147 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003148 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003149 struct brcmf_dcmd *dcmd = data;
3150 struct sk_buff *reply;
3151 int ret;
3152
Arend van Sprield96b8012012-12-05 15:26:02 +01003153 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3154 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003155
3156 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003157 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3158 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003159 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003160 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3161 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003162 if (ret == 0) {
3163 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3164 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3165 ret = cfg80211_testmode_reply(reply);
3166 }
3167 return ret;
3168}
3169#endif
3170
Hante Meuleman1f170112013-02-06 18:40:38 +01003171static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003172{
3173 s32 err;
3174
3175 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003176 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003177 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003178 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003179 return err;
3180 }
3181 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003182 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003183 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003184 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003185 return err;
3186 }
3187 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003188 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003189 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003190 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003191 return err;
3192 }
3193
3194 return 0;
3195}
3196
3197static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3198{
3199 if (is_rsn_ie)
3200 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3201
3202 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3203}
3204
3205static s32
3206brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003207 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003208{
Arend van Sprielac24be62012-10-22 10:36:23 -07003209 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003210 u32 auth = 0; /* d11 open authentication */
3211 u16 count;
3212 s32 err = 0;
3213 s32 len = 0;
3214 u32 i;
3215 u32 wsec;
3216 u32 pval = 0;
3217 u32 gval = 0;
3218 u32 wpa_auth = 0;
3219 u32 offset;
3220 u8 *data;
3221 u16 rsn_cap;
3222 u32 wme_bss_disable;
3223
Arend van Sprield96b8012012-12-05 15:26:02 +01003224 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003225 if (wpa_ie == NULL)
3226 goto exit;
3227
3228 len = wpa_ie->len + TLV_HDR_LEN;
3229 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003230 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003231 if (!is_rsn_ie)
3232 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003233 else
3234 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003235
3236 /* check for multicast cipher suite */
3237 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3238 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003239 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003240 goto exit;
3241 }
3242
3243 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3244 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003245 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003246 goto exit;
3247 }
3248 offset += TLV_OUI_LEN;
3249
3250 /* pick up multicast cipher */
3251 switch (data[offset]) {
3252 case WPA_CIPHER_NONE:
3253 gval = 0;
3254 break;
3255 case WPA_CIPHER_WEP_40:
3256 case WPA_CIPHER_WEP_104:
3257 gval = WEP_ENABLED;
3258 break;
3259 case WPA_CIPHER_TKIP:
3260 gval = TKIP_ENABLED;
3261 break;
3262 case WPA_CIPHER_AES_CCM:
3263 gval = AES_ENABLED;
3264 break;
3265 default:
3266 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003267 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003268 goto exit;
3269 }
3270
3271 offset++;
3272 /* walk thru unicast cipher list and pick up what we recognize */
3273 count = data[offset] + (data[offset + 1] << 8);
3274 offset += WPA_IE_SUITE_COUNT_LEN;
3275 /* Check for unicast suite(s) */
3276 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3277 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003278 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003279 goto exit;
3280 }
3281 for (i = 0; i < count; i++) {
3282 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3283 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003284 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003285 goto exit;
3286 }
3287 offset += TLV_OUI_LEN;
3288 switch (data[offset]) {
3289 case WPA_CIPHER_NONE:
3290 break;
3291 case WPA_CIPHER_WEP_40:
3292 case WPA_CIPHER_WEP_104:
3293 pval |= WEP_ENABLED;
3294 break;
3295 case WPA_CIPHER_TKIP:
3296 pval |= TKIP_ENABLED;
3297 break;
3298 case WPA_CIPHER_AES_CCM:
3299 pval |= AES_ENABLED;
3300 break;
3301 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003302 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003303 }
3304 offset++;
3305 }
3306 /* walk thru auth management suite list and pick up what we recognize */
3307 count = data[offset] + (data[offset + 1] << 8);
3308 offset += WPA_IE_SUITE_COUNT_LEN;
3309 /* Check for auth key management suite(s) */
3310 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3311 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003312 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003313 goto exit;
3314 }
3315 for (i = 0; i < count; i++) {
3316 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3317 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003318 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003319 goto exit;
3320 }
3321 offset += TLV_OUI_LEN;
3322 switch (data[offset]) {
3323 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003324 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003325 wpa_auth |= WPA_AUTH_NONE;
3326 break;
3327 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003328 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003329 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3330 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3331 break;
3332 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003333 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003334 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3335 (wpa_auth |= WPA_AUTH_PSK);
3336 break;
3337 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003338 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003339 }
3340 offset++;
3341 }
3342
3343 if (is_rsn_ie) {
3344 wme_bss_disable = 1;
3345 if ((offset + RSN_CAP_LEN) <= len) {
3346 rsn_cap = data[offset] + (data[offset + 1] << 8);
3347 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3348 wme_bss_disable = 0;
3349 }
3350 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003351 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003352 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003353 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003354 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003355 goto exit;
3356 }
3357 }
3358 /* FOR WPS , set SES_OW_ENABLED */
3359 wsec = (pval | gval | SES_OW_ENABLED);
3360
3361 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003362 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003363 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003364 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003365 goto exit;
3366 }
3367 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003368 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003369 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003370 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003371 goto exit;
3372 }
3373 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003374 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003375 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003376 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003377 goto exit;
3378 }
3379
3380exit:
3381 return err;
3382}
3383
3384static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003385brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003386 struct parsed_vndr_ies *vndr_ies)
3387{
3388 s32 err = 0;
3389 struct brcmf_vs_tlv *vndrie;
3390 struct brcmf_tlv *ie;
3391 struct parsed_vndr_ie_info *parsed_info;
3392 s32 remaining_len;
3393
3394 remaining_len = (s32)vndr_ie_len;
3395 memset(vndr_ies, 0, sizeof(*vndr_ies));
3396
3397 ie = (struct brcmf_tlv *)vndr_ie_buf;
3398 while (ie) {
3399 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3400 goto next;
3401 vndrie = (struct brcmf_vs_tlv *)ie;
3402 /* len should be bigger than OUI length + one */
3403 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003404 brcmf_err("invalid vndr ie. length is too small %d\n",
3405 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003406 goto next;
3407 }
3408 /* if wpa or wme ie, do not add ie */
3409 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3410 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3411 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003412 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003413 goto next;
3414 }
3415
3416 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3417
3418 /* save vndr ie information */
3419 parsed_info->ie_ptr = (char *)vndrie;
3420 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3421 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3422
3423 vndr_ies->count++;
3424
Arend van Sprield96b8012012-12-05 15:26:02 +01003425 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3426 parsed_info->vndrie.oui[0],
3427 parsed_info->vndrie.oui[1],
3428 parsed_info->vndrie.oui[2],
3429 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003430
Arend van Spriel9f440b72013-02-08 15:53:36 +01003431 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003432 break;
3433next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003434 remaining_len -= (ie->len + TLV_HDR_LEN);
3435 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003436 ie = NULL;
3437 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003438 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3439 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003440 }
3441 return err;
3442}
3443
3444static u32
3445brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3446{
3447
3448 __le32 iecount_le;
3449 __le32 pktflag_le;
3450
3451 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3452 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3453
3454 iecount_le = cpu_to_le32(1);
3455 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3456
3457 pktflag_le = cpu_to_le32(pktflag);
3458 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3459
3460 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3461
3462 return ie_len + VNDR_IE_HDR_SIZE;
3463}
3464
Arend van Spriel1332e262012-11-05 16:22:18 -08003465s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3466 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003467{
Arend van Spriel1332e262012-11-05 16:22:18 -08003468 struct brcmf_if *ifp;
3469 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003470 s32 err = 0;
3471 u8 *iovar_ie_buf;
3472 u8 *curr_ie_buf;
3473 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003474 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003475 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003476 u32 del_add_ie_buf_len = 0;
3477 u32 total_ie_buf_len = 0;
3478 u32 parsed_ie_buf_len = 0;
3479 struct parsed_vndr_ies old_vndr_ies;
3480 struct parsed_vndr_ies new_vndr_ies;
3481 struct parsed_vndr_ie_info *vndrie_info;
3482 s32 i;
3483 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003484 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003485
Arend van Spriel1332e262012-11-05 16:22:18 -08003486 if (!vif)
3487 return -ENODEV;
3488 ifp = vif->ifp;
3489 saved_ie = &vif->saved_ie;
3490
Arend van Sprield96b8012012-12-05 15:26:02 +01003491 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003492 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3493 if (!iovar_ie_buf)
3494 return -ENOMEM;
3495 curr_ie_buf = iovar_ie_buf;
Hante Meuleman89286dc2013-02-08 15:53:46 +01003496 switch (pktflag) {
3497 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3498 mgmt_ie_buf = saved_ie->probe_req_ie;
3499 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3500 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3501 break;
3502 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3503 mgmt_ie_buf = saved_ie->probe_res_ie;
3504 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3505 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3506 break;
3507 case BRCMF_VNDR_IE_BEACON_FLAG:
3508 mgmt_ie_buf = saved_ie->beacon_ie;
3509 mgmt_ie_len = &saved_ie->beacon_ie_len;
3510 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
3511 break;
3512 case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
3513 mgmt_ie_buf = saved_ie->assoc_req_ie;
3514 mgmt_ie_len = &saved_ie->assoc_req_ie_len;
3515 mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
3516 break;
3517 default:
3518 err = -EPERM;
3519 brcmf_err("not suitable type\n");
3520 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003521 }
3522
3523 if (vndr_ie_len > mgmt_ie_buf_len) {
3524 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003525 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003526 goto exit;
3527 }
3528
3529 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3530 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3531 ptr = curr_ie_buf;
3532 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3533 for (i = 0; i < new_vndr_ies.count; i++) {
3534 vndrie_info = &new_vndr_ies.ie_info[i];
3535 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3536 vndrie_info->ie_len);
3537 parsed_ie_buf_len += vndrie_info->ie_len;
3538 }
3539 }
3540
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003541 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003542 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3543 (memcmp(mgmt_ie_buf, curr_ie_buf,
3544 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003545 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003546 goto exit;
3547 }
3548
3549 /* parse old vndr_ie */
3550 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3551
3552 /* make a command to delete old ie */
3553 for (i = 0; i < old_vndr_ies.count; i++) {
3554 vndrie_info = &old_vndr_ies.ie_info[i];
3555
Arend van Sprield96b8012012-12-05 15:26:02 +01003556 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3557 vndrie_info->vndrie.id,
3558 vndrie_info->vndrie.len,
3559 vndrie_info->vndrie.oui[0],
3560 vndrie_info->vndrie.oui[1],
3561 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003562
3563 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3564 vndrie_info->ie_ptr,
3565 vndrie_info->ie_len,
3566 "del");
3567 curr_ie_buf += del_add_ie_buf_len;
3568 total_ie_buf_len += del_add_ie_buf_len;
3569 }
3570 }
3571
3572 *mgmt_ie_len = 0;
3573 /* Add if there is any extra IE */
3574 if (mgmt_ie_buf && parsed_ie_buf_len) {
3575 ptr = mgmt_ie_buf;
3576
3577 remained_buf_len = mgmt_ie_buf_len;
3578
3579 /* make a command to add new ie */
3580 for (i = 0; i < new_vndr_ies.count; i++) {
3581 vndrie_info = &new_vndr_ies.ie_info[i];
3582
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003583 /* verify remained buf size before copy data */
3584 if (remained_buf_len < (vndrie_info->vndrie.len +
3585 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003586 brcmf_err("no space in mgmt_ie_buf: len left %d",
3587 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003588 break;
3589 }
3590 remained_buf_len -= (vndrie_info->ie_len +
3591 VNDR_IE_VSIE_OFFSET);
3592
Arend van Sprield96b8012012-12-05 15:26:02 +01003593 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3594 vndrie_info->vndrie.id,
3595 vndrie_info->vndrie.len,
3596 vndrie_info->vndrie.oui[0],
3597 vndrie_info->vndrie.oui[1],
3598 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003599
3600 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3601 vndrie_info->ie_ptr,
3602 vndrie_info->ie_len,
3603 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003604
3605 /* save the parsed IE in wl struct */
3606 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3607 vndrie_info->ie_len);
3608 *mgmt_ie_len += vndrie_info->ie_len;
3609
3610 curr_ie_buf += del_add_ie_buf_len;
3611 total_ie_buf_len += del_add_ie_buf_len;
3612 }
3613 }
3614 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003615 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003616 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003617 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003618 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003619 }
3620
3621exit:
3622 kfree(iovar_ie_buf);
3623 return err;
3624}
3625
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003626s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3627{
3628 s32 pktflags[] = {
3629 BRCMF_VNDR_IE_PRBREQ_FLAG,
3630 BRCMF_VNDR_IE_PRBRSP_FLAG,
3631 BRCMF_VNDR_IE_BEACON_FLAG
3632 };
3633 int i;
3634
3635 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3636 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3637
3638 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3639 return 0;
3640}
3641
Hante Meuleman1a873342012-09-27 14:17:54 +02003642static s32
Hante Meulemana0f07952013-02-08 15:53:47 +01003643brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
3644 struct cfg80211_beacon_data *beacon)
3645{
3646 s32 err;
3647
3648 /* Set Beacon IEs to FW */
3649 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
3650 beacon->tail, beacon->tail_len);
3651 if (err) {
3652 brcmf_err("Set Beacon IE Failed\n");
3653 return err;
3654 }
3655 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
3656
3657 /* Set Probe Response IEs to FW */
3658 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
3659 beacon->proberesp_ies,
3660 beacon->proberesp_ies_len);
3661 if (err)
3662 brcmf_err("Set Probe Resp IE Failed\n");
3663 else
3664 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
3665
3666 return err;
3667}
3668
3669static s32
Hante Meuleman1a873342012-09-27 14:17:54 +02003670brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3671 struct cfg80211_ap_settings *settings)
3672{
3673 s32 ie_offset;
Arend van Sprielac24be62012-10-22 10:36:23 -07003674 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003675 struct brcmf_tlv *ssid_ie;
3676 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003677 s32 err = -EPERM;
3678 struct brcmf_tlv *rsn_ie;
3679 struct brcmf_vs_tlv *wpa_ie;
3680 struct brcmf_join_params join_params;
Hante Meulemana0f07952013-02-08 15:53:47 +01003681 enum nl80211_iftype dev_role;
3682 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003683
Arend van Sprield96b8012012-12-05 15:26:02 +01003684 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3685 cfg80211_get_chandef_type(&settings->chandef),
3686 settings->beacon_interval,
3687 settings->dtim_period);
3688 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3689 settings->ssid, settings->ssid_len, settings->auth_type,
3690 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003691
Hante Meuleman426d0a52013-02-08 15:53:53 +01003692 dev_role = ifp->vif->wdev.iftype;
Hante Meuleman1a873342012-09-27 14:17:54 +02003693
3694 memset(&ssid_le, 0, sizeof(ssid_le));
3695 if (settings->ssid == NULL || settings->ssid_len == 0) {
3696 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3697 ssid_ie = brcmf_parse_tlvs(
3698 (u8 *)&settings->beacon.head[ie_offset],
3699 settings->beacon.head_len - ie_offset,
3700 WLAN_EID_SSID);
3701 if (!ssid_ie)
3702 return -EINVAL;
3703
3704 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3705 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003706 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003707 } else {
3708 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3709 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3710 }
3711
3712 brcmf_set_mpc(ndev, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003713
3714 /* find the RSN_IE */
3715 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3716 settings->beacon.tail_len, WLAN_EID_RSN);
3717
3718 /* find the WPA_IE */
3719 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3720 settings->beacon.tail_len);
3721
Hante Meuleman1a873342012-09-27 14:17:54 +02003722 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003723 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003724 if (wpa_ie != NULL) {
3725 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003726 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003727 if (err < 0)
3728 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003729 } else {
3730 /* RSN IE */
3731 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003732 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003733 if (err < 0)
3734 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003735 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003736 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003737 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003738 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003739 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003740
Hante Meulemana0f07952013-02-08 15:53:47 +01003741 brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
Hante Meuleman1a873342012-09-27 14:17:54 +02003742
3743 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003744 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003745 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003746 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003747 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003748 goto exit;
3749 }
3750 }
3751 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003752 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003753 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003754 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003755 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003756 goto exit;
3757 }
3758 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003759
3760 if (dev_role == NL80211_IFTYPE_AP) {
3761 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
3762 if (err < 0) {
3763 brcmf_err("BRCMF_C_DOWN error %d\n", err);
3764 goto exit;
3765 }
Hante Meuleman2880b862013-02-08 12:06:31 +01003766 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003767 }
3768
Hante Meulemana0f07952013-02-08 15:53:47 +01003769 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003770 if (err < 0) {
Hante Meulemana0f07952013-02-08 15:53:47 +01003771 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003772 goto exit;
3773 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003774 if (dev_role == NL80211_IFTYPE_AP) {
3775 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
3776 if (err < 0) {
3777 brcmf_err("setting AP mode failed %d\n", err);
3778 goto exit;
3779 }
3780 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
3781 if (err < 0) {
3782 brcmf_err("BRCMF_C_UP error (%d)\n", err);
3783 goto exit;
3784 }
3785
3786 memset(&join_params, 0, sizeof(join_params));
3787 /* join parameters starts with ssid */
3788 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3789 /* create softap */
3790 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3791 &join_params, sizeof(join_params));
3792 if (err < 0) {
3793 brcmf_err("SET SSID error (%d)\n", err);
3794 goto exit;
3795 }
3796 brcmf_dbg(TRACE, "AP mode configuration complete\n");
3797 } else {
3798 err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
3799 sizeof(ssid_le));
3800 if (err < 0) {
3801 brcmf_err("setting ssid failed %d\n", err);
3802 goto exit;
3803 }
3804 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3805 bss_enable.enable = cpu_to_le32(1);
3806 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3807 sizeof(bss_enable));
3808 if (err < 0) {
3809 brcmf_err("bss_enable config failed %d\n", err);
3810 goto exit;
3811 }
3812
3813 brcmf_dbg(TRACE, "GO mode configuration complete\n");
3814 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003815 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3816 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003817
3818exit:
3819 if (err)
3820 brcmf_set_mpc(ndev, 1);
3821 return err;
3822}
3823
3824static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3825{
Arend van Sprielc1179032012-10-22 13:55:33 -07003826 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003827 s32 err = -EPERM;
Hante Meuleman426d0a52013-02-08 15:53:53 +01003828 struct brcmf_fil_bss_enable_le bss_enable;
Hante Meuleman1a873342012-09-27 14:17:54 +02003829
Arend van Sprield96b8012012-12-05 15:26:02 +01003830 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003831
Hante Meuleman426d0a52013-02-08 15:53:53 +01003832 if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003833 /* Due to most likely deauths outstanding we sleep */
3834 /* first to make sure they get processed by fw. */
3835 msleep(400);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003836 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003837 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003838 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003839 goto exit;
3840 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003841 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003842 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003843 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003844 goto exit;
3845 }
Hante Meuleman426d0a52013-02-08 15:53:53 +01003846 } else {
3847 bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
3848 bss_enable.enable = cpu_to_le32(0);
3849 err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
3850 sizeof(bss_enable));
3851 if (err < 0)
3852 brcmf_err("bss_enable config failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003853 }
Hante Meuleman426d0a52013-02-08 15:53:53 +01003854 brcmf_set_mpc(ndev, 1);
3855 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3856 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
3857
Hante Meuleman1a873342012-09-27 14:17:54 +02003858exit:
3859 return err;
3860}
3861
Hante Meulemana0f07952013-02-08 15:53:47 +01003862static s32
3863brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
3864 struct cfg80211_beacon_data *info)
3865{
Hante Meulemana0f07952013-02-08 15:53:47 +01003866 struct brcmf_if *ifp = netdev_priv(ndev);
3867 s32 err;
3868
3869 brcmf_dbg(TRACE, "Enter\n");
3870
Hante Meulemana0f07952013-02-08 15:53:47 +01003871 err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
3872
3873 return err;
3874}
3875
Hante Meuleman1a873342012-09-27 14:17:54 +02003876static int
3877brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3878 u8 *mac)
3879{
Hante Meulemana0f07952013-02-08 15:53:47 +01003880 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003881 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003882 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003883 s32 err;
3884
3885 if (!mac)
3886 return -EFAULT;
3887
Arend van Sprield96b8012012-12-05 15:26:02 +01003888 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003889
Hante Meulemana0f07952013-02-08 15:53:47 +01003890 if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
3891 ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
Arend van Sprielce81e312012-10-22 13:55:37 -07003892 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003893 return -EIO;
3894
3895 memcpy(&scbval.ea, mac, ETH_ALEN);
3896 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003897 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003898 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003899 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003900 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman7ab6acd2013-02-08 15:53:58 +01003901
Arend van Sprield96b8012012-12-05 15:26:02 +01003902 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003903 return err;
3904}
3905
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003906
3907static void
3908brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3909 struct wireless_dev *wdev,
3910 u16 frame_type, bool reg)
3911{
3912 struct brcmf_if *ifp = netdev_priv(wdev->netdev);
3913 struct brcmf_cfg80211_vif *vif = ifp->vif;
3914 u16 mgmt_type;
3915
3916 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3917
3918 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
3919 if (reg)
3920 vif->mgmt_rx_reg |= BIT(mgmt_type);
3921 else
Hante Meuleman318a64c2013-02-08 15:53:45 +01003922 vif->mgmt_rx_reg &= ~BIT(mgmt_type);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003923}
3924
3925
3926static int
3927brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3928 struct ieee80211_channel *chan, bool offchan,
3929 unsigned int wait, const u8 *buf, size_t len,
3930 bool no_cck, bool dont_wait_for_ack, u64 *cookie)
3931{
3932 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3933 const struct ieee80211_mgmt *mgmt;
Hante Meulemana0f07952013-02-08 15:53:47 +01003934 struct brcmf_if *ifp;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003935 struct brcmf_cfg80211_vif *vif;
3936 s32 err = 0;
3937 s32 ie_offset;
3938 s32 ie_len;
Hante Meuleman18e2f612013-02-08 15:53:49 +01003939 struct brcmf_fil_action_frame_le *action_frame;
3940 struct brcmf_fil_af_params_le *af_params;
3941 bool ack;
3942 s32 chan_nr;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003943
3944 brcmf_dbg(TRACE, "Enter\n");
3945
3946 *cookie = 0;
3947
3948 mgmt = (const struct ieee80211_mgmt *)buf;
3949
Hante Meulemana0f07952013-02-08 15:53:47 +01003950 if (!ieee80211_is_mgmt(mgmt->frame_control)) {
3951 brcmf_err("Driver only allows MGMT packet type\n");
3952 return -EPERM;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003953 }
Hante Meulemana0f07952013-02-08 15:53:47 +01003954
3955 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
3956 /* Right now the only reason to get a probe response */
3957 /* is for p2p listen response or for p2p GO from */
3958 /* wpa_supplicant. Unfortunately the probe is send */
3959 /* on primary ndev, while dongle wants it on the p2p */
3960 /* vif. Since this is only reason for a probe */
3961 /* response to be sent, the vif is taken from cfg. */
3962 /* If ever desired to send proberesp for non p2p */
3963 /* response then data should be checked for */
3964 /* "DIRECT-". Note in future supplicant will take */
3965 /* dedicated p2p wdev to do this and then this 'hack'*/
3966 /* is not needed anymore. */
3967 ie_offset = DOT11_MGMT_HDR_LEN +
3968 DOT11_BCN_PRB_FIXED_LEN;
3969 ie_len = len - ie_offset;
3970 ifp = netdev_priv(wdev->netdev);
3971 vif = ifp->vif;
3972 if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
3973 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
3974 err = brcmf_vif_set_mgmt_ie(vif,
3975 BRCMF_VNDR_IE_PRBRSP_FLAG,
3976 &buf[ie_offset],
3977 ie_len);
3978 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
3979 GFP_KERNEL);
Hante Meuleman18e2f612013-02-08 15:53:49 +01003980 } else if (ieee80211_is_action(mgmt->frame_control)) {
3981 af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
3982 if (af_params == NULL) {
3983 brcmf_err("unable to allocate frame\n");
3984 err = -ENOMEM;
3985 goto exit;
3986 }
3987 action_frame = &af_params->action_frame;
3988 /* Add the packet Id */
3989 action_frame->packet_id = cpu_to_le32(*cookie);
3990 /* Add BSSID */
3991 memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
3992 memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
3993 /* Add the length exepted for 802.11 header */
3994 action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
3995 /* Add the channel */
3996 chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
3997 af_params->channel = cpu_to_le32(chan_nr);
3998
3999 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
4000 le16_to_cpu(action_frame->len));
4001
4002 brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
4003 *cookie, le16_to_cpu(action_frame->len),
4004 chan->center_freq);
4005
4006 ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
4007 af_params);
4008
4009 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
4010 GFP_KERNEL);
4011 kfree(af_params);
Hante Meulemana0f07952013-02-08 15:53:47 +01004012 } else {
4013 brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
4014 brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4015 }
4016
Hante Meuleman18e2f612013-02-08 15:53:49 +01004017exit:
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004018 return err;
4019}
4020
4021
4022static int
4023brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4024 struct wireless_dev *wdev,
4025 u64 cookie)
4026{
4027 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4028 struct brcmf_cfg80211_vif *vif;
4029 int err = 0;
4030
4031 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
4032
4033 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4034 if (vif == NULL) {
4035 brcmf_err("No p2p device available for probe response\n");
4036 err = -ENODEV;
4037 goto exit;
4038 }
4039 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
4040exit:
4041 return err;
4042}
4043
Arend van Spriel5b435de2011-10-05 13:19:03 +02004044static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01004045 .add_virtual_intf = brcmf_cfg80211_add_iface,
4046 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004047 .change_virtual_intf = brcmf_cfg80211_change_iface,
4048 .scan = brcmf_cfg80211_scan,
4049 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4050 .join_ibss = brcmf_cfg80211_join_ibss,
4051 .leave_ibss = brcmf_cfg80211_leave_ibss,
4052 .get_station = brcmf_cfg80211_get_station,
4053 .set_tx_power = brcmf_cfg80211_set_tx_power,
4054 .get_tx_power = brcmf_cfg80211_get_tx_power,
4055 .add_key = brcmf_cfg80211_add_key,
4056 .del_key = brcmf_cfg80211_del_key,
4057 .get_key = brcmf_cfg80211_get_key,
4058 .set_default_key = brcmf_cfg80211_config_default_key,
4059 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4060 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004061 .connect = brcmf_cfg80211_connect,
4062 .disconnect = brcmf_cfg80211_disconnect,
4063 .suspend = brcmf_cfg80211_suspend,
4064 .resume = brcmf_cfg80211_resume,
4065 .set_pmksa = brcmf_cfg80211_set_pmksa,
4066 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004067 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004068 .start_ap = brcmf_cfg80211_start_ap,
4069 .stop_ap = brcmf_cfg80211_stop_ap,
Hante Meulemana0f07952013-02-08 15:53:47 +01004070 .change_beacon = brcmf_cfg80211_change_beacon,
Hante Meuleman1a873342012-09-27 14:17:54 +02004071 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004072 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4073 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004074 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
4075 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
4076 .remain_on_channel = brcmf_p2p_remain_on_channel,
4077 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004078#ifdef CONFIG_NL80211_TESTMODE
4079 .testmode_cmd = brcmf_cfg80211_testmode
4080#endif
Arend van Spriel5b435de2011-10-05 13:19:03 +02004081};
4082
Arend van Spriel9f440b72013-02-08 15:53:36 +01004083static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004084{
Arend van Spriel9f440b72013-02-08 15:53:36 +01004085 switch (type) {
4086 case NL80211_IFTYPE_AP_VLAN:
4087 case NL80211_IFTYPE_WDS:
4088 case NL80211_IFTYPE_MONITOR:
4089 case NL80211_IFTYPE_MESH_POINT:
4090 return -ENOTSUPP;
4091 case NL80211_IFTYPE_ADHOC:
4092 return WL_MODE_IBSS;
4093 case NL80211_IFTYPE_STATION:
4094 case NL80211_IFTYPE_P2P_CLIENT:
4095 return WL_MODE_BSS;
4096 case NL80211_IFTYPE_AP:
4097 case NL80211_IFTYPE_P2P_GO:
4098 return WL_MODE_AP;
4099 case NL80211_IFTYPE_P2P_DEVICE:
4100 return WL_MODE_P2P;
4101 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004102 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01004103 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004104 }
4105
Arend van Spriel9f440b72013-02-08 15:53:36 +01004106 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004107}
4108
Arend van Spriele5806072012-09-19 22:21:08 +02004109static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4110{
Arend van Spriele5806072012-09-19 22:21:08 +02004111 /* scheduled scan settings */
4112 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4113 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4114 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4115 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02004116}
4117
Arend van Spriel9f440b72013-02-08 15:53:36 +01004118static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
4119 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004120 .max = 2,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004121 .types = BIT(NL80211_IFTYPE_STATION) |
4122 BIT(NL80211_IFTYPE_ADHOC) |
4123 BIT(NL80211_IFTYPE_AP)
4124 },
4125 {
4126 .max = 1,
Hante Meulemandded3d52013-02-08 15:53:57 +01004127 .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
4128 },
4129 {
4130 .max = 1,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004131 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
4132 BIT(NL80211_IFTYPE_P2P_GO)
4133 },
4134};
4135static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
4136 {
Hante Meulemandded3d52013-02-08 15:53:57 +01004137 .max_interfaces = BRCMF_IFACE_MAX_CNT,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004138 .num_different_channels = 1, /* no multi-channel for now */
4139 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
4140 .limits = brcmf_iface_limits
4141 }
4142};
4143
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004144static const struct ieee80211_txrx_stypes
4145brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
4146 [NL80211_IFTYPE_STATION] = {
4147 .tx = 0xffff,
4148 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4149 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4150 },
4151 [NL80211_IFTYPE_P2P_CLIENT] = {
4152 .tx = 0xffff,
4153 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
4154 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
4155 },
4156 [NL80211_IFTYPE_P2P_GO] = {
4157 .tx = 0xffff,
4158 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
4159 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
4160 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
4161 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
4162 BIT(IEEE80211_STYPE_AUTH >> 4) |
4163 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
4164 BIT(IEEE80211_STYPE_ACTION >> 4)
4165 }
4166};
4167
Arend van Spriel3eacf862012-10-22 13:55:30 -07004168static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004169{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004170 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004171 s32 err = 0;
4172
Arend van Spriel3eacf862012-10-22 13:55:30 -07004173 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4174 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004175 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004176 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004177 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004178 set_wiphy_dev(wiphy, phydev);
4179 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004180 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004181 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4182 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4183 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01004184 BIT(NL80211_IFTYPE_AP) |
4185 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Hante Meulemandded3d52013-02-08 15:53:57 +01004186 BIT(NL80211_IFTYPE_P2P_GO) |
4187 BIT(NL80211_IFTYPE_P2P_DEVICE);
Arend van Spriel9f440b72013-02-08 15:53:36 +01004188 wiphy->iface_combinations = brcmf_iface_combos;
4189 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004190 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4191 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
Arend van Spriel5b435de2011-10-05 13:19:03 +02004192 * it as 11a by default.
4193 * This will be updated with
4194 * 11n phy tables in
4195 * "ifconfig up"
4196 * if phy has 11n capability
4197 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07004198 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4199 wiphy->cipher_suites = __wl_cipher_suites;
4200 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004201 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004202 WIPHY_FLAG_OFFCHAN_TX |
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004203 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
4204 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4205 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004206 brcmf_wiphy_pno_params(wiphy);
4207 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004208 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004209 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004210 wiphy_free(wiphy);
4211 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004212 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004213 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004214}
4215
Arend van Spriel3eacf862012-10-22 13:55:30 -07004216struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004217 enum nl80211_iftype type,
4218 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004219{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004220 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004221
Arend van Spriel3eacf862012-10-22 13:55:30 -07004222 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4223 return ERR_PTR(-ENOSPC);
4224
Arend van Spriel33a6b152013-02-08 15:53:39 +01004225 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004226 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004227 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4228 if (!vif)
4229 return ERR_PTR(-ENOMEM);
4230
4231 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004232 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004233
Arend van Spriel9f440b72013-02-08 15:53:36 +01004234 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004235 vif->pm_block = pm_block;
4236 vif->roam_off = -1;
4237
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004238 brcmf_init_prof(&vif->profile);
4239
Arend van Spriel3eacf862012-10-22 13:55:30 -07004240 list_add_tail(&vif->list, &cfg->vif_list);
4241 cfg->vif_cnt++;
4242 return vif;
4243}
4244
Arend van Spriel9f440b72013-02-08 15:53:36 +01004245void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004246{
4247 struct brcmf_cfg80211_info *cfg;
4248 struct wiphy *wiphy;
4249
4250 wiphy = vif->wdev.wiphy;
4251 cfg = wiphy_priv(wiphy);
4252 list_del(&vif->list);
4253 cfg->vif_cnt--;
4254
4255 kfree(vif);
4256 if (!cfg->vif_cnt) {
4257 wiphy_unregister(wiphy);
4258 wiphy_free(wiphy);
4259 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004260}
4261
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004262static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004263{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004264 u32 event = e->event_code;
4265 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004266
4267 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004268 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004269 return true;
4270 }
4271
4272 return false;
4273}
4274
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004275static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004276{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004277 u32 event = e->event_code;
4278 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004279
4280 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004281 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004282 return true;
4283 }
4284 return false;
4285}
4286
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004287static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004288 const struct brcmf_event_msg *e)
4289{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004290 u32 event = e->event_code;
4291 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004292
4293 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004294 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4295 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004296 return true;
4297 }
4298
4299 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004300 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004301 return true;
4302 }
4303
4304 return false;
4305}
4306
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004307static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004308{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004309 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004310
4311 kfree(conn_info->req_ie);
4312 conn_info->req_ie = NULL;
4313 conn_info->req_ie_len = 0;
4314 kfree(conn_info->resp_ie);
4315 conn_info->resp_ie = NULL;
4316 conn_info->resp_ie_len = 0;
4317}
4318
Hante Meuleman89286dc2013-02-08 15:53:46 +01004319static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
4320 struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004321{
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004322 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004323 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004324 u32 req_len;
4325 u32 resp_len;
4326 s32 err = 0;
4327
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004328 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004329
Arend van Sprielac24be62012-10-22 10:36:23 -07004330 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4331 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004332 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004333 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004334 return err;
4335 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004336 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004337 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004338 req_len = le32_to_cpu(assoc_info->req_len);
4339 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004340 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004341 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004342 cfg->extra_buf,
4343 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004344 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004345 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004346 return err;
4347 }
4348 conn_info->req_ie_len = req_len;
4349 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004350 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004351 GFP_KERNEL);
4352 } else {
4353 conn_info->req_ie_len = 0;
4354 conn_info->req_ie = NULL;
4355 }
4356 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004357 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004358 cfg->extra_buf,
4359 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004360 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004361 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004362 return err;
4363 }
4364 conn_info->resp_ie_len = resp_len;
4365 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004366 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004367 GFP_KERNEL);
4368 } else {
4369 conn_info->resp_ie_len = 0;
4370 conn_info->resp_ie = NULL;
4371 }
Arend van Spriel16886732012-12-05 15:26:04 +01004372 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4373 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004374
4375 return err;
4376}
4377
4378static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004379brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004380 struct net_device *ndev,
4381 const struct brcmf_event_msg *e)
4382{
Arend van Sprielc1179032012-10-22 13:55:33 -07004383 struct brcmf_if *ifp = netdev_priv(ndev);
4384 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004385 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4386 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004387 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004388 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004389 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004390 u32 freq;
4391 s32 err = 0;
4392 u32 target_channel;
Franky Lina180b832012-10-10 11:13:09 -07004393 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004394
Arend van Sprield96b8012012-12-05 15:26:02 +01004395 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004396
Hante Meuleman89286dc2013-02-08 15:53:46 +01004397 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004398 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004399 brcmf_update_bss_info(cfg, ifp);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004400
Franky Lina180b832012-10-10 11:13:09 -07004401 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4402 if (buf == NULL) {
4403 err = -ENOMEM;
4404 goto done;
4405 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004406
Franky Lina180b832012-10-10 11:13:09 -07004407 /* data sent to dongle has to be little endian */
4408 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004409 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004410 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004411
4412 if (err)
4413 goto done;
4414
4415 bi = (struct brcmf_bss_info_le *)(buf + 4);
4416 target_channel = bi->ctl_ch ? bi->ctl_ch :
4417 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004418
4419 if (target_channel <= CH_MAX_2G_CHANNEL)
4420 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4421 else
4422 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4423
4424 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4425 notify_channel = ieee80211_get_channel(wiphy, freq);
4426
Franky Lina180b832012-10-10 11:13:09 -07004427done:
4428 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004429 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004430 conn_info->req_ie, conn_info->req_ie_len,
4431 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004432 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004433
Arend van Sprielc1179032012-10-22 13:55:33 -07004434 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004435 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004436 return err;
4437}
4438
4439static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004440brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004441 struct net_device *ndev, const struct brcmf_event_msg *e,
4442 bool completed)
4443{
Arend van Sprielc1179032012-10-22 13:55:33 -07004444 struct brcmf_if *ifp = netdev_priv(ndev);
4445 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004446 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004447 s32 err = 0;
4448
Arend van Sprield96b8012012-12-05 15:26:02 +01004449 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004450
Arend van Sprielc1179032012-10-22 13:55:33 -07004451 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4452 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004453 if (completed) {
Hante Meuleman89286dc2013-02-08 15:53:46 +01004454 brcmf_get_assoc_ies(cfg, ifp);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004455 memcpy(profile->bssid, e->addr, ETH_ALEN);
Hante Meuleman89286dc2013-02-08 15:53:46 +01004456 brcmf_update_bss_info(cfg, ifp);
4457 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4458 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004459 }
4460 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004461 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004462 conn_info->req_ie,
4463 conn_info->req_ie_len,
4464 conn_info->resp_ie,
4465 conn_info->resp_ie_len,
4466 completed ? WLAN_STATUS_SUCCESS :
4467 WLAN_STATUS_AUTH_TIMEOUT,
4468 GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004469 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4470 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004471 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004472 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004473 return err;
4474}
4475
4476static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004477brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004478 struct net_device *ndev,
4479 const struct brcmf_event_msg *e, void *data)
4480{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004481 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004482 u32 event = e->event_code;
4483 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004484 struct station_info sinfo;
4485
Arend van Spriel16886732012-12-05 15:26:04 +01004486 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004487 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4488 ndev != cfg_to_ndev(cfg)) {
4489 brcmf_dbg(CONN, "AP mode link down\n");
4490 complete(&cfg->vif_disabled);
4491 return 0;
4492 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004493
Hante Meuleman1a873342012-09-27 14:17:54 +02004494 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004495 (reason == BRCMF_E_STATUS_SUCCESS)) {
4496 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004497 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4498 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004499 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004500 return -EINVAL;
4501 }
4502 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004503 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004504 generation++;
4505 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004506 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004507 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4508 (event == BRCMF_E_DEAUTH_IND) ||
4509 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004510 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004511 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004512 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004513}
4514
4515static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004516brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004517 const struct brcmf_event_msg *e, void *data)
4518{
Arend van Spriel19937322012-11-05 16:22:32 -08004519 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4520 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004521 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004522 s32 err = 0;
4523
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004524 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004525 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004526 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004527 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004528 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004529 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004530 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004531 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004532 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4533 &ifp->vif->sme_state);
4534 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4535 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004536 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004537 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004538 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004539 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004540 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004541 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004542 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004543 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004544 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004545 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004546 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004547 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004548 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004549 if (ndev != cfg_to_ndev(cfg))
4550 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004551 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004552 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004553 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4554 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004555 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004556 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004557 }
4558
4559 return err;
4560}
4561
4562static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004563brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004564 const struct brcmf_event_msg *e, void *data)
4565{
Arend van Spriel19937322012-11-05 16:22:32 -08004566 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004567 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004568 u32 event = e->event_code;
4569 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004570
4571 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004572 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004573 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004574 else
Arend van Spriel19937322012-11-05 16:22:32 -08004575 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004576 }
4577
4578 return err;
4579}
4580
4581static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004582brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004583 const struct brcmf_event_msg *e, void *data)
4584{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004585 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004586 enum nl80211_key_type key_type;
4587
4588 if (flags & BRCMF_EVENT_MSG_GROUP)
4589 key_type = NL80211_KEYTYPE_GROUP;
4590 else
4591 key_type = NL80211_KEYTYPE_PAIRWISE;
4592
Arend van Spriel19937322012-11-05 16:22:32 -08004593 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004594 NULL, GFP_KERNEL);
4595
4596 return 0;
4597}
4598
Arend van Sprield3c0b632013-02-08 15:53:37 +01004599static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4600 const struct brcmf_event_msg *e, void *data)
4601{
4602 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4603 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4604 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4605 struct brcmf_cfg80211_vif *vif;
4606
4607 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4608 ifevent->action, ifevent->flags, ifevent->ifidx,
4609 ifevent->bssidx);
4610
Arend van Sprield3c0b632013-02-08 15:53:37 +01004611 mutex_lock(&event->vif_event_lock);
4612 event->action = ifevent->action;
4613 vif = event->vif;
4614
4615 switch (ifevent->action) {
4616 case BRCMF_E_IF_ADD:
4617 /* waiting process may have timed out */
Wei Yongjundc4a7872013-02-22 21:32:20 +08004618 if (!cfg->vif_event.vif) {
4619 mutex_unlock(&event->vif_event_lock);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004620 return -EBADF;
Wei Yongjundc4a7872013-02-22 21:32:20 +08004621 }
Arend van Sprield3c0b632013-02-08 15:53:37 +01004622
4623 ifp->vif = vif;
4624 vif->ifp = ifp;
4625 vif->wdev.netdev = ifp->ndev;
4626 ifp->ndev->ieee80211_ptr = &vif->wdev;
4627 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4628 mutex_unlock(&event->vif_event_lock);
4629 wake_up(&event->vif_wq);
Hante Meuleman4b3a89d2013-02-08 15:54:01 +01004630 return 0;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004631
4632 case BRCMF_E_IF_DEL:
4633 ifp->vif = NULL;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004634 mutex_unlock(&event->vif_event_lock);
4635 /* event may not be upon user request */
4636 if (brcmf_cfg80211_vif_event_armed(cfg))
4637 wake_up(&event->vif_wq);
4638 return 0;
4639
Hante Meuleman7a5c1f62013-02-08 15:53:44 +01004640 case BRCMF_E_IF_CHANGE:
4641 mutex_unlock(&event->vif_event_lock);
4642 wake_up(&event->vif_wq);
4643 return 0;
4644
Arend van Sprield3c0b632013-02-08 15:53:37 +01004645 default:
4646 mutex_unlock(&event->vif_event_lock);
4647 break;
4648 }
4649 return -EINVAL;
4650}
4651
Arend van Spriel5b435de2011-10-05 13:19:03 +02004652static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4653{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004654 conf->frag_threshold = (u32)-1;
4655 conf->rts_threshold = (u32)-1;
4656 conf->retry_short = (u32)-1;
4657 conf->retry_long = (u32)-1;
4658 conf->tx_power = -1;
4659}
4660
Arend van Spriel5c36b992012-11-14 18:46:05 -08004661static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004662{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004663 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4664 brcmf_notify_connect_status);
4665 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4666 brcmf_notify_connect_status);
4667 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4668 brcmf_notify_connect_status);
4669 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4670 brcmf_notify_connect_status);
4671 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4672 brcmf_notify_connect_status);
4673 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4674 brcmf_notify_connect_status);
4675 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4676 brcmf_notify_roaming_status);
4677 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4678 brcmf_notify_mic_status);
4679 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4680 brcmf_notify_connect_status);
4681 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4682 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004683 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4684 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004685 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004686 brcmf_p2p_notify_rx_mgmt_p2p_probereq);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004687 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4688 brcmf_p2p_notify_listen_complete);
Hante Meulemane6da3402013-02-08 15:53:48 +01004689 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4690 brcmf_p2p_notify_action_frame_rx);
Hante Meuleman18e2f612013-02-08 15:53:49 +01004691 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
4692 brcmf_p2p_notify_action_tx_complete);
Hante Meuleman6eda4e22013-02-08 15:54:02 +01004693 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
4694 brcmf_p2p_notify_action_tx_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004695}
4696
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004697static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004698{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004699 kfree(cfg->conf);
4700 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004701 kfree(cfg->escan_ioctl_buf);
4702 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004703 kfree(cfg->extra_buf);
4704 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004705 kfree(cfg->pmk_list);
4706 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004707}
4708
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004709static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004710{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004711 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4712 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004713 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004714 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4715 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004716 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004717 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4718 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004719 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004720 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4721 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004722 goto init_priv_mem_out;
4723
4724 return 0;
4725
4726init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004727 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004728
4729 return -ENOMEM;
4730}
4731
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004732static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004733{
4734 s32 err = 0;
4735
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004736 cfg->scan_request = NULL;
4737 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004738 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004739 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004740 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004741 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004742 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004743 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004744 if (err)
4745 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004746 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004747 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004748 brcmf_init_escan(cfg);
4749 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004750 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004751 return err;
4752}
4753
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004754static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004755{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004756 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004757 brcmf_abort_scanning(cfg);
4758 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004759}
4760
Arend van Sprield3c0b632013-02-08 15:53:37 +01004761static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4762{
4763 init_waitqueue_head(&event->vif_wq);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004764 mutex_init(&event->vif_event_lock);
4765}
4766
Arend van Sprield9cb2592012-12-05 15:25:54 +01004767struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4768 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004769{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004770 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004771 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004772 struct wiphy *wiphy;
4773 struct brcmf_cfg80211_vif *vif;
4774 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004775 s32 err = 0;
4776
4777 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004778 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004779 return NULL;
4780 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004781
Arend van Spriel3eacf862012-10-22 13:55:30 -07004782 ifp = netdev_priv(ndev);
4783 wiphy = brcmf_setup_wiphy(busdev);
4784 if (IS_ERR(wiphy))
4785 return NULL;
4786
4787 cfg = wiphy_priv(wiphy);
4788 cfg->wiphy = wiphy;
4789 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004790 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004791 INIT_LIST_HEAD(&cfg->vif_list);
4792
Arend van Sprield3c0b632013-02-08 15:53:37 +01004793 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004794 if (IS_ERR(vif)) {
4795 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004796 return NULL;
4797 }
4798
Arend van Sprield3c0b632013-02-08 15:53:37 +01004799 vif->ifp = ifp;
4800 vif->wdev.netdev = ndev;
4801 ndev->ieee80211_ptr = &vif->wdev;
4802 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4803
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004804 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004805 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004806 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004807 goto cfg80211_attach_out;
4808 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004809 ifp->vif = vif;
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004810
4811 err = brcmf_p2p_attach(cfg);
4812 if (err) {
4813 brcmf_err("P2P initilisation failed (%d)\n", err);
4814 goto cfg80211_p2p_attach_out;
4815 }
4816
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004817 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004818
Hante Meuleman2fde59d2013-02-08 15:53:52 +01004819cfg80211_p2p_attach_out:
4820 wl_deinit_priv(cfg);
4821
Arend van Spriel5b435de2011-10-05 13:19:03 +02004822cfg80211_attach_out:
Arend van Spriel3eacf862012-10-22 13:55:30 -07004823 brcmf_free_vif(vif);
Hante Meuleman2880b862013-02-08 12:06:31 +01004824 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004825 return NULL;
4826}
4827
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004828void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004829{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004830 struct brcmf_cfg80211_vif *vif;
4831 struct brcmf_cfg80211_vif *tmp;
4832
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004833 wl_deinit_priv(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004834 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4835 brcmf_free_vif(vif);
4836 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004837}
4838
Arend van Spriel5b435de2011-10-05 13:19:03 +02004839static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004840brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004841{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004842 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02004843 __le32 roamtrigger[2];
4844 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02004845
4846 /*
4847 * Setup timeout if Beacons are lost and roam is
4848 * off to report link down
4849 */
4850 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004851 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004852 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004853 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004854 goto dongle_rom_out;
4855 }
4856 }
4857
4858 /*
4859 * Enable/Disable built-in roaming to allow supplicant
4860 * to take care of roaming
4861 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004862 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07004863 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004864 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004865 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004866 goto dongle_rom_out;
4867 }
4868
Arend van Sprielf588bc02011-10-12 20:51:22 +02004869 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4870 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004871 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004872 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004873 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004874 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004875 goto dongle_rom_out;
4876 }
4877
Arend van Sprielf588bc02011-10-12 20:51:22 +02004878 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4879 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004880 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004881 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004882 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004883 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004884 goto dongle_rom_out;
4885 }
4886
4887dongle_rom_out:
4888 return err;
4889}
4890
4891static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004892brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02004893 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004894{
4895 s32 err = 0;
4896
Arend van Sprielac24be62012-10-22 10:36:23 -07004897 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004898 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004899 if (err) {
4900 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004901 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004902 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004903 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004904 goto dongle_scantime_out;
4905 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004906 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004907 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004908 if (err) {
4909 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004910 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004911 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004912 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004913 goto dongle_scantime_out;
4914 }
4915
Arend van Sprielac24be62012-10-22 10:36:23 -07004916 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004917 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004918 if (err) {
4919 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004920 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004921 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004922 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004923 goto dongle_scantime_out;
4924 }
4925
4926dongle_scantime_out:
4927 return err;
4928}
4929
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004930static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004931{
Arend van Sprielac24be62012-10-22 10:36:23 -07004932 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004933 struct wiphy *wiphy;
4934 s32 phy_list;
4935 s8 phy;
4936 s32 err = 0;
4937
Hante Meulemanb87e2c42012-11-14 18:46:23 -08004938 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004939 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004940 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004941 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004942 return err;
4943 }
4944
Hante Meuleman3ba81372012-09-19 22:21:13 +02004945 phy = ((char *)&phy_list)[0];
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004946 brcmf_dbg(INFO, "%c phy\n", phy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004947 if (phy == 'n' || phy == 'a') {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004948 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004949 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4950 }
4951
4952 return err;
4953}
4954
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004955static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004956{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004957 return wl_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004958}
4959
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004960static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004961{
4962 struct net_device *ndev;
4963 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01004964 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004965 s32 power_mode;
4966 s32 err = 0;
4967
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004968 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004969 return err;
4970
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004971 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004972 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01004973 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004974
Hante Meuleman40a23292013-01-02 15:22:51 +01004975 /* make sure RF is ready for work */
4976 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
4977
4978 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
4979 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004980
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004981 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01004982 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004983 if (err)
4984 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004985 brcmf_dbg(INFO, "power save set to %s\n",
4986 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004987
Hante Meuleman40a23292013-01-02 15:22:51 +01004988 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004989 if (err)
4990 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07004991 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
4992 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01004993 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004994 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004995 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004996 if (err)
4997 goto default_conf_out;
4998
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004999 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01005000default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02005001
5002 return err;
5003
5004}
5005
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005006static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005007{
Arend van Sprielc1179032012-10-22 13:55:33 -07005008 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005009
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005010 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005011}
5012
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005013static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005014{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005015 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07005016
Arend van Spriel5b435de2011-10-05 13:19:03 +02005017 /*
5018 * While going down, if associated with AP disassociate
5019 * from AP to save power
5020 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01005021 if (check_vif_up(ifp->vif)) {
5022 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005023
5024 /* Make sure WPA_Supplicant receives all the event
5025 generated due to DISASSOC call to the fw to keep
5026 the state fw and WPA_Supplicant state consistent
5027 */
5028 brcmf_delay(500);
5029 }
5030
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005031 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005032 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005033
Arend van Spriel5b435de2011-10-05 13:19:03 +02005034 return 0;
5035}
5036
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005037s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005038{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005039 struct brcmf_if *ifp = netdev_priv(ndev);
5040 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005041 s32 err = 0;
5042
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005043 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005044 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005045 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005046
5047 return err;
5048}
5049
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005050s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005051{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005052 struct brcmf_if *ifp = netdev_priv(ndev);
5053 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005054 s32 err = 0;
5055
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005056 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08005057 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005058 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005059
5060 return err;
5061}
5062
Arend van Spriel9f440b72013-02-08 15:53:36 +01005063u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
5064{
5065 struct brcmf_cfg80211_vif *vif;
5066 bool result = 0;
5067
5068 list_for_each_entry(vif, &cfg->vif_list, list) {
5069 if (test_bit(state, &vif->sme_state))
5070 result++;
5071 }
5072 return result;
5073}
Arend van Sprield3c0b632013-02-08 15:53:37 +01005074
5075static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
5076 u8 action)
5077{
5078 u8 evt_action;
5079
5080 mutex_lock(&event->vif_event_lock);
5081 evt_action = event->action;
5082 mutex_unlock(&event->vif_event_lock);
5083 return evt_action == action;
5084}
5085
5086void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
5087 struct brcmf_cfg80211_vif *vif)
5088{
5089 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5090
5091 mutex_lock(&event->vif_event_lock);
5092 event->vif = vif;
5093 event->action = 0;
5094 mutex_unlock(&event->vif_event_lock);
5095}
5096
5097bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
5098{
5099 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5100 bool armed;
5101
5102 mutex_lock(&event->vif_event_lock);
5103 armed = event->vif != NULL;
5104 mutex_unlock(&event->vif_event_lock);
5105
5106 return armed;
5107}
5108int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
5109 u8 action, ulong timeout)
5110{
5111 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
5112
5113 return wait_event_timeout(event->vif_wq,
5114 vif_event_equals(event, action), timeout);
5115}
5116