blob: d792c3b2331a6c034c88a83663257d7fe8ce1ab8 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020021#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020022#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023
24#include <brcmu_utils.h>
25#include <defs.h>
26#include <brcmu_wifi.h>
27#include "dhd.h"
Arend van Spriel16886732012-12-05 15:26:04 +010028#include "dhd_dbg.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010029#include "p2p.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020030#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070031#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020032
Arend van Spriele5806072012-09-19 22:21:08 +020033#define BRCMF_SCAN_IE_LEN_MAX 2048
34#define BRCMF_PNO_VERSION 2
35#define BRCMF_PNO_TIME 30
36#define BRCMF_PNO_REPEAT 4
37#define BRCMF_PNO_FREQ_EXPO_MAX 3
38#define BRCMF_PNO_MAX_PFN_COUNT 16
39#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
40#define BRCMF_PNO_HIDDEN_BIT 2
41#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
42#define BRCMF_PNO_SCAN_COMPLETE 1
43#define BRCMF_PNO_SCAN_INCOMPLETE 0
44
Arend van Spriel9f440b72013-02-08 15:53:36 +010045#define BRCMF_IFACE_MAX_CNT 3
Arend van Spriel3eacf862012-10-22 13:55:30 -070046
Hante Meuleman1a873342012-09-27 14:17:54 +020047#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
48#define WPA_OUI_TYPE 1
49#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
50#define WME_OUI_TYPE 2
51
52#define VS_IE_FIXED_HDR_LEN 6
53#define WPA_IE_VERSION_LEN 2
54#define WPA_IE_MIN_OUI_LEN 4
55#define WPA_IE_SUITE_COUNT_LEN 2
56
57#define WPA_CIPHER_NONE 0 /* None */
58#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
59#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
60#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
61#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
62
63#define RSN_AKM_NONE 0 /* None (IBSS) */
64#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
65#define RSN_AKM_PSK 2 /* Pre-shared Key */
66#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
67#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
68
69#define VNDR_IE_CMD_LEN 4 /* length of the set command
70 * string :"add", "del" (+ NUL)
71 */
72#define VNDR_IE_COUNT_OFFSET 4
73#define VNDR_IE_PKTFLAG_OFFSET 8
74#define VNDR_IE_VSIE_OFFSET 12
75#define VNDR_IE_HDR_SIZE 12
Arend van Spriel9f440b72013-02-08 15:53:36 +010076#define VNDR_IE_PARSE_LIMIT 5
Hante Meuleman1a873342012-09-27 14:17:54 +020077
78#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
79#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020080
Arend van Spriel5b435de2011-10-05 13:19:03 +020081#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
82 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
83
Arend van Sprielce81e312012-10-22 13:55:37 -070084static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020085{
Arend van Sprielc1179032012-10-22 13:55:33 -070086 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +010087 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
88 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +020089 return false;
90 }
91 return true;
92}
93
94#define CHAN2G(_channel, _freq, _flags) { \
95 .band = IEEE80211_BAND_2GHZ, \
96 .center_freq = (_freq), \
97 .hw_value = (_channel), \
98 .flags = (_flags), \
99 .max_antenna_gain = 0, \
100 .max_power = 30, \
101}
102
103#define CHAN5G(_channel, _flags) { \
104 .band = IEEE80211_BAND_5GHZ, \
105 .center_freq = 5000 + (5 * (_channel)), \
106 .hw_value = (_channel), \
107 .flags = (_flags), \
108 .max_antenna_gain = 0, \
109 .max_power = 30, \
110}
111
112#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
113#define RATETAB_ENT(_rateid, _flags) \
114 { \
115 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
116 .hw_value = (_rateid), \
117 .flags = (_flags), \
118 }
119
120static struct ieee80211_rate __wl_rates[] = {
121 RATETAB_ENT(BRCM_RATE_1M, 0),
122 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
123 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
124 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
125 RATETAB_ENT(BRCM_RATE_6M, 0),
126 RATETAB_ENT(BRCM_RATE_9M, 0),
127 RATETAB_ENT(BRCM_RATE_12M, 0),
128 RATETAB_ENT(BRCM_RATE_18M, 0),
129 RATETAB_ENT(BRCM_RATE_24M, 0),
130 RATETAB_ENT(BRCM_RATE_36M, 0),
131 RATETAB_ENT(BRCM_RATE_48M, 0),
132 RATETAB_ENT(BRCM_RATE_54M, 0),
133};
134
135#define wl_a_rates (__wl_rates + 4)
136#define wl_a_rates_size 8
137#define wl_g_rates (__wl_rates + 0)
138#define wl_g_rates_size 12
139
140static struct ieee80211_channel __wl_2ghz_channels[] = {
141 CHAN2G(1, 2412, 0),
142 CHAN2G(2, 2417, 0),
143 CHAN2G(3, 2422, 0),
144 CHAN2G(4, 2427, 0),
145 CHAN2G(5, 2432, 0),
146 CHAN2G(6, 2437, 0),
147 CHAN2G(7, 2442, 0),
148 CHAN2G(8, 2447, 0),
149 CHAN2G(9, 2452, 0),
150 CHAN2G(10, 2457, 0),
151 CHAN2G(11, 2462, 0),
152 CHAN2G(12, 2467, 0),
153 CHAN2G(13, 2472, 0),
154 CHAN2G(14, 2484, 0),
155};
156
157static struct ieee80211_channel __wl_5ghz_a_channels[] = {
158 CHAN5G(34, 0), CHAN5G(36, 0),
159 CHAN5G(38, 0), CHAN5G(40, 0),
160 CHAN5G(42, 0), CHAN5G(44, 0),
161 CHAN5G(46, 0), CHAN5G(48, 0),
162 CHAN5G(52, 0), CHAN5G(56, 0),
163 CHAN5G(60, 0), CHAN5G(64, 0),
164 CHAN5G(100, 0), CHAN5G(104, 0),
165 CHAN5G(108, 0), CHAN5G(112, 0),
166 CHAN5G(116, 0), CHAN5G(120, 0),
167 CHAN5G(124, 0), CHAN5G(128, 0),
168 CHAN5G(132, 0), CHAN5G(136, 0),
169 CHAN5G(140, 0), CHAN5G(149, 0),
170 CHAN5G(153, 0), CHAN5G(157, 0),
171 CHAN5G(161, 0), CHAN5G(165, 0),
172 CHAN5G(184, 0), CHAN5G(188, 0),
173 CHAN5G(192, 0), CHAN5G(196, 0),
174 CHAN5G(200, 0), CHAN5G(204, 0),
175 CHAN5G(208, 0), CHAN5G(212, 0),
176 CHAN5G(216, 0),
177};
178
179static struct ieee80211_channel __wl_5ghz_n_channels[] = {
180 CHAN5G(32, 0), CHAN5G(34, 0),
181 CHAN5G(36, 0), CHAN5G(38, 0),
182 CHAN5G(40, 0), CHAN5G(42, 0),
183 CHAN5G(44, 0), CHAN5G(46, 0),
184 CHAN5G(48, 0), CHAN5G(50, 0),
185 CHAN5G(52, 0), CHAN5G(54, 0),
186 CHAN5G(56, 0), CHAN5G(58, 0),
187 CHAN5G(60, 0), CHAN5G(62, 0),
188 CHAN5G(64, 0), CHAN5G(66, 0),
189 CHAN5G(68, 0), CHAN5G(70, 0),
190 CHAN5G(72, 0), CHAN5G(74, 0),
191 CHAN5G(76, 0), CHAN5G(78, 0),
192 CHAN5G(80, 0), CHAN5G(82, 0),
193 CHAN5G(84, 0), CHAN5G(86, 0),
194 CHAN5G(88, 0), CHAN5G(90, 0),
195 CHAN5G(92, 0), CHAN5G(94, 0),
196 CHAN5G(96, 0), CHAN5G(98, 0),
197 CHAN5G(100, 0), CHAN5G(102, 0),
198 CHAN5G(104, 0), CHAN5G(106, 0),
199 CHAN5G(108, 0), CHAN5G(110, 0),
200 CHAN5G(112, 0), CHAN5G(114, 0),
201 CHAN5G(116, 0), CHAN5G(118, 0),
202 CHAN5G(120, 0), CHAN5G(122, 0),
203 CHAN5G(124, 0), CHAN5G(126, 0),
204 CHAN5G(128, 0), CHAN5G(130, 0),
205 CHAN5G(132, 0), CHAN5G(134, 0),
206 CHAN5G(136, 0), CHAN5G(138, 0),
207 CHAN5G(140, 0), CHAN5G(142, 0),
208 CHAN5G(144, 0), CHAN5G(145, 0),
209 CHAN5G(146, 0), CHAN5G(147, 0),
210 CHAN5G(148, 0), CHAN5G(149, 0),
211 CHAN5G(150, 0), CHAN5G(151, 0),
212 CHAN5G(152, 0), CHAN5G(153, 0),
213 CHAN5G(154, 0), CHAN5G(155, 0),
214 CHAN5G(156, 0), CHAN5G(157, 0),
215 CHAN5G(158, 0), CHAN5G(159, 0),
216 CHAN5G(160, 0), CHAN5G(161, 0),
217 CHAN5G(162, 0), CHAN5G(163, 0),
218 CHAN5G(164, 0), CHAN5G(165, 0),
219 CHAN5G(166, 0), CHAN5G(168, 0),
220 CHAN5G(170, 0), CHAN5G(172, 0),
221 CHAN5G(174, 0), CHAN5G(176, 0),
222 CHAN5G(178, 0), CHAN5G(180, 0),
223 CHAN5G(182, 0), CHAN5G(184, 0),
224 CHAN5G(186, 0), CHAN5G(188, 0),
225 CHAN5G(190, 0), CHAN5G(192, 0),
226 CHAN5G(194, 0), CHAN5G(196, 0),
227 CHAN5G(198, 0), CHAN5G(200, 0),
228 CHAN5G(202, 0), CHAN5G(204, 0),
229 CHAN5G(206, 0), CHAN5G(208, 0),
230 CHAN5G(210, 0), CHAN5G(212, 0),
231 CHAN5G(214, 0), CHAN5G(216, 0),
232 CHAN5G(218, 0), CHAN5G(220, 0),
233 CHAN5G(222, 0), CHAN5G(224, 0),
234 CHAN5G(226, 0), CHAN5G(228, 0),
235};
236
237static struct ieee80211_supported_band __wl_band_2ghz = {
238 .band = IEEE80211_BAND_2GHZ,
239 .channels = __wl_2ghz_channels,
240 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
241 .bitrates = wl_g_rates,
242 .n_bitrates = wl_g_rates_size,
243};
244
245static struct ieee80211_supported_band __wl_band_5ghz_a = {
246 .band = IEEE80211_BAND_5GHZ,
247 .channels = __wl_5ghz_a_channels,
248 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
249 .bitrates = wl_a_rates,
250 .n_bitrates = wl_a_rates_size,
251};
252
253static struct ieee80211_supported_band __wl_band_5ghz_n = {
254 .band = IEEE80211_BAND_5GHZ,
255 .channels = __wl_5ghz_n_channels,
256 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
257 .bitrates = wl_a_rates,
258 .n_bitrates = wl_a_rates_size,
259};
260
261static const u32 __wl_cipher_suites[] = {
262 WLAN_CIPHER_SUITE_WEP40,
263 WLAN_CIPHER_SUITE_WEP104,
264 WLAN_CIPHER_SUITE_TKIP,
265 WLAN_CIPHER_SUITE_CCMP,
266 WLAN_CIPHER_SUITE_AES_CMAC,
267};
268
Hante Meuleman1a873342012-09-27 14:17:54 +0200269/* Vendor specific ie. id = 221, oui and type defines exact ie */
270struct brcmf_vs_tlv {
271 u8 id;
272 u8 len;
273 u8 oui[3];
274 u8 oui_type;
275};
276
277struct parsed_vndr_ie_info {
278 u8 *ie_ptr;
279 u32 ie_len; /* total length including id & length field */
280 struct brcmf_vs_tlv vndrie;
281};
282
283struct parsed_vndr_ies {
284 u32 count;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100285 struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
Hante Meuleman1a873342012-09-27 14:17:54 +0200286};
287
Alwin Beukersef6ac172011-10-12 20:51:26 +0200288/* Quarter dBm units to mW
289 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
290 * Table is offset so the last entry is largest mW value that fits in
291 * a u16.
292 */
293
294#define QDBM_OFFSET 153 /* Offset for first entry */
295#define QDBM_TABLE_LEN 40 /* Table size */
296
297/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
298 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
299 */
300#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
301
302/* Largest mW value that will round down to the last table entry,
303 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
304 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
305 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
306 */
307#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
308
309static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
310/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
311/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
312/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
313/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
314/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
315/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
316};
317
318static u16 brcmf_qdbm_to_mw(u8 qdbm)
319{
320 uint factor = 1;
321 int idx = qdbm - QDBM_OFFSET;
322
323 if (idx >= QDBM_TABLE_LEN)
324 /* clamp to max u16 mW value */
325 return 0xFFFF;
326
327 /* scale the qdBm index up to the range of the table 0-40
328 * where an offset of 40 qdBm equals a factor of 10 mW.
329 */
330 while (idx < 0) {
331 idx += 40;
332 factor *= 10;
333 }
334
335 /* return the mW value scaled down to the correct factor of 10,
336 * adding in factor/2 to get proper rounding.
337 */
338 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
339}
340
341static u8 brcmf_mw_to_qdbm(u16 mw)
342{
343 u8 qdbm;
344 int offset;
345 uint mw_uint = mw;
346 uint boundary;
347
348 /* handle boundary case */
349 if (mw_uint <= 1)
350 return 0;
351
352 offset = QDBM_OFFSET;
353
354 /* move mw into the range of the table */
355 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
356 mw_uint *= 10;
357 offset -= 40;
358 }
359
360 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
361 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
362 nqdBm_to_mW_map[qdbm]) / 2;
363 if (mw_uint < boundary)
364 break;
365 }
366
367 qdbm += (u8) offset;
368
369 return qdbm;
370}
371
Arend van Spriel9f440b72013-02-08 15:53:36 +0100372u16 channel_to_chanspec(struct ieee80211_channel *ch)
Arend van Spriel6e186162012-10-22 10:36:22 -0700373{
374 u16 chanspec;
375
376 chanspec = ieee80211_frequency_to_channel(ch->center_freq);
377 chanspec &= WL_CHANSPEC_CHAN_MASK;
378
379 if (ch->band == IEEE80211_BAND_2GHZ)
380 chanspec |= WL_CHANSPEC_BAND_2G;
381 else
382 chanspec |= WL_CHANSPEC_BAND_5G;
383
Hante Meuleman17012612013-02-06 18:40:44 +0100384 chanspec |= WL_CHANSPEC_BW_20;
385 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
386
Arend van Spriel6e186162012-10-22 10:36:22 -0700387 return chanspec;
388}
389
Arend van Spriel5b435de2011-10-05 13:19:03 +0200390static void convert_key_from_CPU(struct brcmf_wsec_key *key,
391 struct brcmf_wsec_key_le *key_le)
392{
393 key_le->index = cpu_to_le32(key->index);
394 key_le->len = cpu_to_le32(key->len);
395 key_le->algo = cpu_to_le32(key->algo);
396 key_le->flags = cpu_to_le32(key->flags);
397 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
398 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
399 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
400 memcpy(key_le->data, key->data, sizeof(key->data));
401 memcpy(key_le->ea, key->ea, sizeof(key->ea));
402}
403
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200404static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700405send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200406{
407 int err;
408 struct brcmf_wsec_key_le key_le;
409
410 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200411
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700412 brcmf_netdev_wait_pend8021x(ndev);
413
Arend van Sprielac24be62012-10-22 10:36:23 -0700414 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700415 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200416
Arend van Spriel5b435de2011-10-05 13:19:03 +0200417 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100418 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200419 return err;
420}
421
Arend van Spriel9f440b72013-02-08 15:53:36 +0100422static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
423 const char *name,
424 enum nl80211_iftype type,
425 u32 *flags,
426 struct vif_params *params)
427{
428 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
429 switch (type) {
430 case NL80211_IFTYPE_ADHOC:
431 case NL80211_IFTYPE_STATION:
432 case NL80211_IFTYPE_AP:
433 case NL80211_IFTYPE_AP_VLAN:
434 case NL80211_IFTYPE_WDS:
435 case NL80211_IFTYPE_MONITOR:
436 case NL80211_IFTYPE_MESH_POINT:
437 return ERR_PTR(-EOPNOTSUPP);
438 case NL80211_IFTYPE_P2P_CLIENT:
439 case NL80211_IFTYPE_P2P_GO:
440 return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
441 case NL80211_IFTYPE_UNSPECIFIED:
442 case NL80211_IFTYPE_P2P_DEVICE:
443 default:
444 return ERR_PTR(-EINVAL);
445 }
446}
447
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100448static void brcmf_set_mpc(struct net_device *ndev, int mpc)
449{
450 struct brcmf_if *ifp = netdev_priv(ndev);
451 s32 err = 0;
452
453 if (check_vif_up(ifp->vif)) {
454 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
455 if (err) {
456 brcmf_err("fail to set mpc\n");
457 return;
458 }
459 brcmf_dbg(INFO, "MPC : %d\n", mpc);
460 }
461}
462
463static s32
464brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
465 struct net_device *ndev,
466 bool aborted, bool fw_abort)
467{
468 struct brcmf_scan_params_le params_le;
469 struct cfg80211_scan_request *scan_request;
470 s32 err = 0;
471
472 brcmf_dbg(SCAN, "Enter\n");
473
474 /* clear scan request, because the FW abort can cause a second call */
475 /* to this functon and might cause a double cfg80211_scan_done */
476 scan_request = cfg->scan_request;
477 cfg->scan_request = NULL;
478
479 if (timer_pending(&cfg->escan_timeout))
480 del_timer_sync(&cfg->escan_timeout);
481
482 if (fw_abort) {
483 /* Do a scan abort to stop the driver's scan engine */
484 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
485 memset(&params_le, 0, sizeof(params_le));
486 memset(params_le.bssid, 0xFF, ETH_ALEN);
487 params_le.bss_type = DOT11_BSSTYPE_ANY;
488 params_le.scan_type = 0;
489 params_le.channel_num = cpu_to_le32(1);
490 params_le.nprobes = cpu_to_le32(1);
491 params_le.active_time = cpu_to_le32(-1);
492 params_le.passive_time = cpu_to_le32(-1);
493 params_le.home_time = cpu_to_le32(-1);
494 /* Scan is aborted by setting channel_list[0] to -1 */
495 params_le.channel_list[0] = cpu_to_le16(-1);
496 /* E-Scan (or anyother type) can be aborted by SCAN */
497 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
498 &params_le, sizeof(params_le));
499 if (err)
500 brcmf_err("Scan abort failed\n");
501 }
502 /*
503 * e-scan can be initiated by scheduled scan
504 * which takes precedence.
505 */
506 if (cfg->sched_escan) {
507 brcmf_dbg(SCAN, "scheduled scan completed\n");
508 cfg->sched_escan = false;
509 if (!aborted)
510 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
511 brcmf_set_mpc(ndev, 1);
512 } else if (scan_request) {
513 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
514 aborted ? "Aborted" : "Done");
515 cfg80211_scan_done(scan_request, aborted);
516 brcmf_set_mpc(ndev, 1);
517 }
518 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
519 brcmf_err("Scan complete while device not scanning\n");
520 return -EPERM;
521 }
522
523 return err;
524}
525
Arend van Spriel9f440b72013-02-08 15:53:36 +0100526static
527int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
528{
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100529 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
530 struct net_device *ndev = wdev->netdev;
531
532 /* vif event pending in firmware */
533 if (brcmf_cfg80211_vif_event_armed(cfg))
534 return -EBUSY;
535
536 if (ndev) {
537 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
538 cfg->escan_info.ndev == ndev)
539 brcmf_notify_escan_complete(cfg, ndev, true,
540 true);
541
542 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
543 }
544
Arend van Spriel9f440b72013-02-08 15:53:36 +0100545 switch (wdev->iftype) {
546 case NL80211_IFTYPE_ADHOC:
547 case NL80211_IFTYPE_STATION:
548 case NL80211_IFTYPE_AP:
549 case NL80211_IFTYPE_AP_VLAN:
550 case NL80211_IFTYPE_WDS:
551 case NL80211_IFTYPE_MONITOR:
552 case NL80211_IFTYPE_MESH_POINT:
553 return -EOPNOTSUPP;
554 case NL80211_IFTYPE_P2P_CLIENT:
555 case NL80211_IFTYPE_P2P_GO:
556 return brcmf_p2p_del_vif(wiphy, wdev);
557 case NL80211_IFTYPE_UNSPECIFIED:
558 case NL80211_IFTYPE_P2P_DEVICE:
559 default:
560 return -EINVAL;
561 }
562 return -EOPNOTSUPP;
563}
564
Arend van Spriel5b435de2011-10-05 13:19:03 +0200565static s32
566brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
567 enum nl80211_iftype type, u32 *flags,
568 struct vif_params *params)
569{
Arend van Sprielc1179032012-10-22 13:55:33 -0700570 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100571 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200572 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200573 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200574 s32 err = 0;
575
Arend van Sprield96b8012012-12-05 15:26:02 +0100576 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200577
578 switch (type) {
579 case NL80211_IFTYPE_MONITOR:
580 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100581 brcmf_err("type (%d) : currently we do not support this type\n",
582 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200583 return -EOPNOTSUPP;
584 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100585 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200586 infra = 0;
587 break;
588 case NL80211_IFTYPE_STATION:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100589 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200590 infra = 1;
591 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200592 case NL80211_IFTYPE_AP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100593 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200594 ap = 1;
595 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200596 default:
597 err = -EINVAL;
598 goto done;
599 }
600
Hante Meuleman1a873342012-09-27 14:17:54 +0200601 if (ap) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100602 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100603 brcmf_dbg(INFO, "IF Type = AP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200604 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100605 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200606 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100607 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200608 err = -EAGAIN;
609 goto done;
610 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100611 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
612 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200613 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200614 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200615
616done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100617 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200618
619 return err;
620}
621
Hante Meulemane756af52012-09-11 21:18:52 +0200622static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
623 struct cfg80211_scan_request *request)
624{
625 u32 n_ssids;
626 u32 n_channels;
627 s32 i;
628 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200629 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200630 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200631 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200632
Arend van Sprielba40d162012-10-22 13:55:38 -0700633 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200634 params_le->bss_type = DOT11_BSSTYPE_ANY;
635 params_le->scan_type = 0;
636 params_le->channel_num = 0;
637 params_le->nprobes = cpu_to_le32(-1);
638 params_le->active_time = cpu_to_le32(-1);
639 params_le->passive_time = cpu_to_le32(-1);
640 params_le->home_time = cpu_to_le32(-1);
641 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
642
643 /* if request is null exit so it will be all channel broadcast scan */
644 if (!request)
645 return;
646
647 n_ssids = request->n_ssids;
648 n_channels = request->n_channels;
649 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100650 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
651 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200652 if (n_channels > 0) {
653 for (i = 0; i < n_channels; i++) {
Arend van Spriel6e186162012-10-22 10:36:22 -0700654 chanspec = channel_to_chanspec(request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100655 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
656 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200657 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200658 }
659 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100660 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200661 }
662 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100663 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200664 if (n_ssids > 0) {
665 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
666 n_channels * sizeof(u16);
667 offset = roundup(offset, sizeof(u32));
668 ptr = (char *)params_le + offset;
669 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200670 memset(&ssid_le, 0, sizeof(ssid_le));
671 ssid_le.SSID_len =
672 cpu_to_le32(request->ssids[i].ssid_len);
673 memcpy(ssid_le.SSID, request->ssids[i].ssid,
674 request->ssids[i].ssid_len);
675 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100676 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200677 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100678 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
679 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200680 memcpy(ptr, &ssid_le, sizeof(ssid_le));
681 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200682 }
683 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100684 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200685 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100686 brcmf_dbg(SCAN, "SSID %s len=%d\n",
687 params_le->ssid_le.SSID,
688 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200689 params_le->ssid_le.SSID_len =
690 cpu_to_le32(request->ssids->ssid_len);
691 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
692 request->ssids->ssid_len);
693 }
694 }
695 /* Adding mask to channel numbers */
696 params_le->channel_num =
697 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
698 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
699}
700
701static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200702brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
Hante Meulemane756af52012-09-11 21:18:52 +0200703 struct cfg80211_scan_request *request, u16 action)
704{
705 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
706 offsetof(struct brcmf_escan_params_le, params_le);
707 struct brcmf_escan_params_le *params;
708 s32 err = 0;
709
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100710 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200711
712 if (request != NULL) {
713 /* Allocate space for populating ssids in struct */
714 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
715
716 /* Allocate space for populating ssids in struct */
717 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
718 }
719
720 params = kzalloc(params_size, GFP_KERNEL);
721 if (!params) {
722 err = -ENOMEM;
723 goto exit;
724 }
725 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
726 brcmf_escan_prep(&params->params_le, request);
727 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
728 params->action = cpu_to_le16(action);
729 params->sync_id = cpu_to_le16(0x1234);
730
Arend van Sprielac24be62012-10-22 10:36:23 -0700731 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
732 params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200733 if (err) {
734 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100735 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200736 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100737 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200738 }
739
740 kfree(params);
741exit:
742 return err;
743}
744
745static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200746brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Hante Meulemane756af52012-09-11 21:18:52 +0200747 struct net_device *ndev, struct cfg80211_scan_request *request)
748{
749 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700750 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200751 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100752 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200753
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100754 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriel9f440b72013-02-08 15:53:36 +0100755 escan->ndev = ndev;
756 escan->wiphy = wiphy;
757 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700758 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700759 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700760 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200761 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100762 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200763 return err;
764 }
765 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200766 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200767 results->version = 0;
768 results->count = 0;
769 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
770
Arend van Spriel9f440b72013-02-08 15:53:36 +0100771 err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200772 if (err)
773 brcmf_set_mpc(ndev, 1);
774 return err;
775}
776
777static s32
778brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
779 struct cfg80211_scan_request *request,
780 struct cfg80211_ssid *this_ssid)
781{
Arend van Sprielc1179032012-10-22 13:55:33 -0700782 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200783 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Hante Meulemane756af52012-09-11 21:18:52 +0200784 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800785 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700786 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200787 bool escan_req;
788 bool spec_scan;
789 s32 err;
790 u32 SSID_len;
791
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100792 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200793
Arend van Sprielc1179032012-10-22 13:55:33 -0700794 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100795 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200796 return -EAGAIN;
797 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700798 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100799 brcmf_err("Scanning being aborted: status (%lu)\n",
800 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200801 return -EAGAIN;
802 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700803 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100804 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200805 return -EAGAIN;
806 }
807
808 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200809 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200810 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
811
812 escan_req = false;
813 if (request) {
814 /* scan bss */
815 ssids = request->ssids;
816 escan_req = true;
817 } else {
818 /* scan in ibss */
819 /* we don't do escan in ibss */
820 ssids = this_ssid;
821 }
822
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200823 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700824 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200825 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100826 cfg->escan_info.run = brcmf_run_escan;
827 err = brcmf_p2p_scan_prep(wiphy, request);
828 if (err)
829 goto scan_out;
830
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200831 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800832 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200833 goto scan_out;
834 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100835 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
836 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200837 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
838 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
839 sr->ssid_le.SSID_len = cpu_to_le32(0);
840 spec_scan = false;
841 if (SSID_len) {
842 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
843 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
844 spec_scan = true;
845 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100846 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200847
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700848 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700849 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700850 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200851 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100852 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200853 goto scan_out;
854 }
855 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700856 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700857 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200858 if (err) {
859 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100860 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
861 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200862 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100863 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200864
865 brcmf_set_mpc(ndev, 1);
866 goto scan_out;
867 }
868 }
869
870 return 0;
871
872scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700873 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200874 if (timer_pending(&cfg->escan_timeout))
875 del_timer_sync(&cfg->escan_timeout);
876 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200877 return err;
878}
879
Arend van Spriel5b435de2011-10-05 13:19:03 +0200880static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700881brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200882{
Johannes Bergfd014282012-06-18 19:17:03 +0200883 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200884 s32 err = 0;
885
Arend van Sprield96b8012012-12-05 15:26:02 +0100886 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200887
Arend van Sprielce81e312012-10-22 13:55:37 -0700888 if (!check_vif_up(container_of(request->wdev,
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700889 struct brcmf_cfg80211_vif, wdev)))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200890 return -EIO;
891
Hante Meulemanf07998952012-11-05 16:22:13 -0800892 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200893
Arend van Spriel5b435de2011-10-05 13:19:03 +0200894 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100895 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200896
Arend van Sprield96b8012012-12-05 15:26:02 +0100897 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200898 return err;
899}
900
901static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
902{
903 s32 err = 0;
904
Arend van Sprielac24be62012-10-22 10:36:23 -0700905 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
906 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200907 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100908 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200909
910 return err;
911}
912
913static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
914{
915 s32 err = 0;
916
Arend van Sprielac24be62012-10-22 10:36:23 -0700917 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
918 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200919 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100920 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200921
922 return err;
923}
924
925static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
926{
927 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -0800928 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200929
Arend van Sprielac24be62012-10-22 10:36:23 -0700930 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200931 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100932 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200933 return err;
934 }
935 return err;
936}
937
938static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
939{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200940 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
941 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700942 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200943 s32 err = 0;
944
Arend van Sprield96b8012012-12-05 15:26:02 +0100945 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -0700946 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200947 return -EIO;
948
949 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200950 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
951 cfg->conf->rts_threshold = wiphy->rts_threshold;
952 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200953 if (!err)
954 goto done;
955 }
956 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200957 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
958 cfg->conf->frag_threshold = wiphy->frag_threshold;
959 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200960 if (!err)
961 goto done;
962 }
963 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200964 && (cfg->conf->retry_long != wiphy->retry_long)) {
965 cfg->conf->retry_long = wiphy->retry_long;
966 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200967 if (!err)
968 goto done;
969 }
970 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200971 && (cfg->conf->retry_short != wiphy->retry_short)) {
972 cfg->conf->retry_short = wiphy->retry_short;
973 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200974 if (!err)
975 goto done;
976 }
977
978done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100979 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200980 return err;
981}
982
Arend van Spriel5b435de2011-10-05 13:19:03 +0200983static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
984{
985 memset(prof, 0, sizeof(*prof));
986}
987
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100988static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200989{
Arend van Spriel5b435de2011-10-05 13:19:03 +0200990 s32 err = 0;
991
Arend van Sprield96b8012012-12-05 15:26:02 +0100992 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200993
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100994 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100995 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100996 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -0700997 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200998 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100999 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001000 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001001 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001002 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001003 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001004}
1005
1006static s32
1007brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1008 struct cfg80211_ibss_params *params)
1009{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001010 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001011 struct brcmf_if *ifp = netdev_priv(ndev);
1012 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001013 struct brcmf_join_params join_params;
1014 size_t join_params_size = 0;
1015 s32 err = 0;
1016 s32 wsec = 0;
1017 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001018 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001019
Arend van Sprield96b8012012-12-05 15:26:02 +01001020 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001021 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001022 return -EIO;
1023
1024 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001025 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001026 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001027 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001028 return -EOPNOTSUPP;
1029 }
1030
Arend van Sprielc1179032012-10-22 13:55:33 -07001031 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001032
1033 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001034 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001035 else
Arend van Spriel16886732012-12-05 15:26:04 +01001036 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001037
Johannes Berg683b6d32012-11-08 21:25:48 +01001038 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001039 brcmf_dbg(CONN, "channel: %d\n",
1040 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001041 else
Arend van Spriel16886732012-12-05 15:26:04 +01001042 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001043
1044 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001045 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001046 else
Arend van Spriel16886732012-12-05 15:26:04 +01001047 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001048
1049 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001050 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001051 else
Arend van Spriel16886732012-12-05 15:26:04 +01001052 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001053
1054 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001055 brcmf_dbg(CONN, "beacon interval: %d\n",
1056 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001057 else
Arend van Spriel16886732012-12-05 15:26:04 +01001058 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001059
1060 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001061 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001062 else
Arend van Spriel16886732012-12-05 15:26:04 +01001063 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001064
1065 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001066 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001067 else
Arend van Spriel16886732012-12-05 15:26:04 +01001068 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001069
1070 /* Configure Privacy for starter */
1071 if (params->privacy)
1072 wsec |= WEP_ENABLED;
1073
Arend van Sprielc1179032012-10-22 13:55:33 -07001074 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001075 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001076 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001077 goto done;
1078 }
1079
1080 /* Configure Beacon Interval for starter */
1081 if (params->beacon_interval)
1082 bcnprd = params->beacon_interval;
1083 else
1084 bcnprd = 100;
1085
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001086 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001087 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001088 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001089 goto done;
1090 }
1091
1092 /* Configure required join parameter */
1093 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1094
1095 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001096 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1097 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1098 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1099 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001100 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001101
1102 /* BSSID */
1103 if (params->bssid) {
1104 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1105 join_params_size = sizeof(join_params.ssid_le) +
1106 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001107 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001108 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001109 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001110 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001111 }
1112
Arend van Spriel5b435de2011-10-05 13:19:03 +02001113 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001114 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001115 u32 target_channel;
1116
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001117 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001118 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001119 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001120 if (params->channel_fixed) {
1121 /* adding chanspec */
Hante Meuleman17012612013-02-06 18:40:44 +01001122 chanspec = channel_to_chanspec(params->chandef.chan);
1123 join_params.params_le.chanspec_list[0] =
1124 cpu_to_le16(chanspec);
1125 join_params.params_le.chanspec_num = cpu_to_le32(1);
1126 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001127 }
1128
1129 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001130 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001131 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001132 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001133 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001134 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001135 goto done;
1136 }
1137 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001138 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001139
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001140 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001141
1142
Arend van Sprielc1179032012-10-22 13:55:33 -07001143 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001144 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001145 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001146 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001147 goto done;
1148 }
1149
1150done:
1151 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001152 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001153 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001154 return err;
1155}
1156
1157static s32
1158brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1159{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001160 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001161 s32 err = 0;
1162
Arend van Sprield96b8012012-12-05 15:26:02 +01001163 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001164 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001165 return -EIO;
1166
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001167 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001168
Arend van Sprield96b8012012-12-05 15:26:02 +01001169 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170
1171 return err;
1172}
1173
1174static s32 brcmf_set_wpa_version(struct net_device *ndev,
1175 struct cfg80211_connect_params *sme)
1176{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001177 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001178 struct brcmf_cfg80211_security *sec;
1179 s32 val = 0;
1180 s32 err = 0;
1181
1182 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1183 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1184 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1185 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1186 else
1187 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001188 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001189 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001190 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001191 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001192 return err;
1193 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001194 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001195 sec->wpa_versions = sme->crypto.wpa_versions;
1196 return err;
1197}
1198
1199static s32 brcmf_set_auth_type(struct net_device *ndev,
1200 struct cfg80211_connect_params *sme)
1201{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001202 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001203 struct brcmf_cfg80211_security *sec;
1204 s32 val = 0;
1205 s32 err = 0;
1206
1207 switch (sme->auth_type) {
1208 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1209 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001210 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001211 break;
1212 case NL80211_AUTHTYPE_SHARED_KEY:
1213 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001214 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001215 break;
1216 case NL80211_AUTHTYPE_AUTOMATIC:
1217 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001218 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001219 break;
1220 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001221 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222 default:
1223 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001224 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001225 break;
1226 }
1227
Arend van Sprielac24be62012-10-22 10:36:23 -07001228 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001229 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001230 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001231 return err;
1232 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001233 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001234 sec->auth_type = sme->auth_type;
1235 return err;
1236}
1237
1238static s32
1239brcmf_set_set_cipher(struct net_device *ndev,
1240 struct cfg80211_connect_params *sme)
1241{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001242 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001243 struct brcmf_cfg80211_security *sec;
1244 s32 pval = 0;
1245 s32 gval = 0;
1246 s32 err = 0;
1247
1248 if (sme->crypto.n_ciphers_pairwise) {
1249 switch (sme->crypto.ciphers_pairwise[0]) {
1250 case WLAN_CIPHER_SUITE_WEP40:
1251 case WLAN_CIPHER_SUITE_WEP104:
1252 pval = WEP_ENABLED;
1253 break;
1254 case WLAN_CIPHER_SUITE_TKIP:
1255 pval = TKIP_ENABLED;
1256 break;
1257 case WLAN_CIPHER_SUITE_CCMP:
1258 pval = AES_ENABLED;
1259 break;
1260 case WLAN_CIPHER_SUITE_AES_CMAC:
1261 pval = AES_ENABLED;
1262 break;
1263 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001264 brcmf_err("invalid cipher pairwise (%d)\n",
1265 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001266 return -EINVAL;
1267 }
1268 }
1269 if (sme->crypto.cipher_group) {
1270 switch (sme->crypto.cipher_group) {
1271 case WLAN_CIPHER_SUITE_WEP40:
1272 case WLAN_CIPHER_SUITE_WEP104:
1273 gval = WEP_ENABLED;
1274 break;
1275 case WLAN_CIPHER_SUITE_TKIP:
1276 gval = TKIP_ENABLED;
1277 break;
1278 case WLAN_CIPHER_SUITE_CCMP:
1279 gval = AES_ENABLED;
1280 break;
1281 case WLAN_CIPHER_SUITE_AES_CMAC:
1282 gval = AES_ENABLED;
1283 break;
1284 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001285 brcmf_err("invalid cipher group (%d)\n",
1286 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001287 return -EINVAL;
1288 }
1289 }
1290
Arend van Spriel16886732012-12-05 15:26:04 +01001291 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Arend van Sprielac24be62012-10-22 10:36:23 -07001292 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001293 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001294 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001295 return err;
1296 }
1297
Arend van Spriel06bb1232012-09-27 14:17:56 +02001298 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001299 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1300 sec->cipher_group = sme->crypto.cipher_group;
1301
1302 return err;
1303}
1304
1305static s32
1306brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1307{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001308 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001309 struct brcmf_cfg80211_security *sec;
1310 s32 val = 0;
1311 s32 err = 0;
1312
1313 if (sme->crypto.n_akm_suites) {
Arend van Sprielac24be62012-10-22 10:36:23 -07001314 err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
1315 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001316 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001317 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001318 return err;
1319 }
1320 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1321 switch (sme->crypto.akm_suites[0]) {
1322 case WLAN_AKM_SUITE_8021X:
1323 val = WPA_AUTH_UNSPECIFIED;
1324 break;
1325 case WLAN_AKM_SUITE_PSK:
1326 val = WPA_AUTH_PSK;
1327 break;
1328 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001329 brcmf_err("invalid cipher group (%d)\n",
1330 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001331 return -EINVAL;
1332 }
1333 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1334 switch (sme->crypto.akm_suites[0]) {
1335 case WLAN_AKM_SUITE_8021X:
1336 val = WPA2_AUTH_UNSPECIFIED;
1337 break;
1338 case WLAN_AKM_SUITE_PSK:
1339 val = WPA2_AUTH_PSK;
1340 break;
1341 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001342 brcmf_err("invalid cipher group (%d)\n",
1343 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001344 return -EINVAL;
1345 }
1346 }
1347
Arend van Spriel16886732012-12-05 15:26:04 +01001348 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001349 err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
1350 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001351 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001352 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001353 return err;
1354 }
1355 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001356 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001357 sec->wpa_auth = sme->crypto.akm_suites[0];
1358
1359 return err;
1360}
1361
1362static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001363brcmf_set_sharedkey(struct net_device *ndev,
1364 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001365{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001366 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001367 struct brcmf_cfg80211_security *sec;
1368 struct brcmf_wsec_key key;
1369 s32 val;
1370 s32 err = 0;
1371
Arend van Spriel16886732012-12-05 15:26:04 +01001372 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001373
Roland Vossena718e2f2011-10-12 20:51:24 +02001374 if (sme->key_len == 0)
1375 return 0;
1376
Arend van Spriel06bb1232012-09-27 14:17:56 +02001377 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001378 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1379 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001380
1381 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1382 return 0;
1383
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001384 if (!(sec->cipher_pairwise &
1385 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1386 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001387
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001388 memset(&key, 0, sizeof(key));
1389 key.len = (u32) sme->key_len;
1390 key.index = (u32) sme->key_idx;
1391 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001392 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001393 return -EINVAL;
1394 }
1395 memcpy(key.data, sme->key, key.len);
1396 key.flags = BRCMF_PRIMARY_KEY;
1397 switch (sec->cipher_pairwise) {
1398 case WLAN_CIPHER_SUITE_WEP40:
1399 key.algo = CRYPTO_ALGO_WEP1;
1400 break;
1401 case WLAN_CIPHER_SUITE_WEP104:
1402 key.algo = CRYPTO_ALGO_WEP128;
1403 break;
1404 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001405 brcmf_err("Invalid algorithm (%d)\n",
1406 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001407 return -EINVAL;
1408 }
1409 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001410 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1411 key.len, key.index, key.algo);
1412 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001413 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001414 if (err)
1415 return err;
1416
1417 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001418 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001419 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001420 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001421 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001422 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001423 }
1424 return err;
1425}
1426
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001427static
1428enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1429 enum nl80211_auth_type type)
1430{
1431 u32 ci;
1432 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1433 /* shift to ignore chip revision */
1434 ci = brcmf_get_chip_info(ifp) >> 4;
1435 switch (ci) {
1436 case 43236:
1437 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1438 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1439 default:
1440 break;
1441 }
1442 }
1443 return type;
1444}
1445
Arend van Spriel5b435de2011-10-05 13:19:03 +02001446static s32
1447brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001448 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001449{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001450 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001451 struct brcmf_if *ifp = netdev_priv(ndev);
1452 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453 struct ieee80211_channel *chan = sme->channel;
1454 struct brcmf_join_params join_params;
1455 size_t join_params_size;
1456 struct brcmf_ssid ssid;
Hante Meuleman17012612013-02-06 18:40:44 +01001457 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458
1459 s32 err = 0;
1460
Arend van Sprield96b8012012-12-05 15:26:02 +01001461 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001462 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001463 return -EIO;
1464
1465 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001466 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467 return -EOPNOTSUPP;
1468 }
1469
Arend van Sprielc1179032012-10-22 13:55:33 -07001470 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001471
1472 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001473 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001474 ieee80211_frequency_to_channel(chan->center_freq);
Hante Meuleman17012612013-02-06 18:40:44 +01001475 chanspec = channel_to_chanspec(chan);
1476 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1477 cfg->channel, chan->center_freq, chanspec);
1478 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001479 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001480 chanspec = 0;
1481 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001483 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001484
1485 err = brcmf_set_wpa_version(ndev, sme);
1486 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001487 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001488 goto done;
1489 }
1490
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001491 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001492 err = brcmf_set_auth_type(ndev, sme);
1493 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001494 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001495 goto done;
1496 }
1497
1498 err = brcmf_set_set_cipher(ndev, sme);
1499 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001500 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001501 goto done;
1502 }
1503
1504 err = brcmf_set_key_mgmt(ndev, sme);
1505 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001506 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001507 goto done;
1508 }
1509
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001510 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001512 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001513 goto done;
1514 }
1515
1516 memset(&join_params, 0, sizeof(join_params));
1517 join_params_size = sizeof(join_params.ssid_le);
1518
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001519 profile->ssid.SSID_len = min_t(u32,
1520 sizeof(ssid.SSID), (u32)sme->ssid_len);
1521 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
1522 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1523 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524
Arend van Sprielba40d162012-10-22 13:55:38 -07001525 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001526
1527 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
Arend van Spriel16886732012-12-05 15:26:04 +01001528 brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
1529 ssid.SSID, ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001530
Hante Meuleman17012612013-02-06 18:40:44 +01001531 if (cfg->channel) {
1532 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1533 join_params.params_le.chanspec_num = cpu_to_le32(1);
1534 join_params_size += sizeof(join_params.params_le);
1535 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001536 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001537 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001539 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001540
1541done:
1542 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001543 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001544 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001545 return err;
1546}
1547
1548static s32
1549brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1550 u16 reason_code)
1551{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001552 struct brcmf_if *ifp = netdev_priv(ndev);
1553 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001554 struct brcmf_scb_val_le scbval;
1555 s32 err = 0;
1556
Arend van Sprield96b8012012-12-05 15:26:02 +01001557 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001558 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001559 return -EIO;
1560
Arend van Sprielc1179032012-10-22 13:55:33 -07001561 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001562
Arend van Spriel06bb1232012-09-27 14:17:56 +02001563 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001564 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001565 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001566 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001567 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001568 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001569
Arend van Sprield96b8012012-12-05 15:26:02 +01001570 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001571 return err;
1572}
1573
1574static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001575brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001576 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001577{
1578
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001579 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001580 struct net_device *ndev = cfg_to_ndev(cfg);
1581 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 u16 txpwrmw;
1583 s32 err = 0;
1584 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001585 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001586
Arend van Sprield96b8012012-12-05 15:26:02 +01001587 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001588 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001589 return -EIO;
1590
1591 switch (type) {
1592 case NL80211_TX_POWER_AUTOMATIC:
1593 break;
1594 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001595 case NL80211_TX_POWER_FIXED:
1596 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001597 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001598 err = -EINVAL;
1599 goto done;
1600 }
1601 break;
1602 }
1603 /* Make sure radio is off or on as far as software is concerned */
1604 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001605 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001606 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001607 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001608
1609 if (dbm > 0xffff)
1610 txpwrmw = 0xffff;
1611 else
1612 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001613 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1614 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001615 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001616 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001617 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001618
1619done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001620 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001621 return err;
1622}
1623
Johannes Bergc8442112012-10-24 10:17:18 +02001624static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1625 struct wireless_dev *wdev,
1626 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001627{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001628 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001629 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001630 s32 txpwrdbm;
1631 u8 result;
1632 s32 err = 0;
1633
Arend van Sprield96b8012012-12-05 15:26:02 +01001634 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001635 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001636 return -EIO;
1637
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001638 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001639 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001640 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001641 goto done;
1642 }
1643
1644 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001645 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646
1647done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001648 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001649 return err;
1650}
1651
1652static s32
1653brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1654 u8 key_idx, bool unicast, bool multicast)
1655{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001656 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001657 u32 index;
1658 u32 wsec;
1659 s32 err = 0;
1660
Arend van Sprield96b8012012-12-05 15:26:02 +01001661 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001662 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001663 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001664 return -EIO;
1665
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001666 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001667 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001668 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001669 goto done;
1670 }
1671
1672 if (wsec & WEP_ENABLED) {
1673 /* Just select a new current key */
1674 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001675 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001676 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001677 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001678 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001679 }
1680done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001681 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001682 return err;
1683}
1684
1685static s32
1686brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1687 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1688{
1689 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001690 s32 err = 0;
1691
1692 memset(&key, 0, sizeof(key));
1693 key.index = (u32) key_idx;
1694 /* Instead of bcast for ea address for default wep keys,
1695 driver needs it to be Null */
1696 if (!is_multicast_ether_addr(mac_addr))
1697 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1698 key.len = (u32) params->key_len;
1699 /* check for key index change */
1700 if (key.len == 0) {
1701 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001702 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001703 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001704 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001705 } else {
1706 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001707 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001708 return -EINVAL;
1709 }
1710
Arend van Spriel16886732012-12-05 15:26:04 +01001711 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001712 memcpy(key.data, params->key, key.len);
1713
1714 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1715 u8 keybuf[8];
1716 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1717 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1718 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1719 }
1720
1721 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1722 if (params->seq && params->seq_len == 6) {
1723 /* rx iv */
1724 u8 *ivptr;
1725 ivptr = (u8 *) params->seq;
1726 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1727 (ivptr[3] << 8) | ivptr[2];
1728 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1729 key.iv_initialized = true;
1730 }
1731
1732 switch (params->cipher) {
1733 case WLAN_CIPHER_SUITE_WEP40:
1734 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001735 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001736 break;
1737 case WLAN_CIPHER_SUITE_WEP104:
1738 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001739 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001740 break;
1741 case WLAN_CIPHER_SUITE_TKIP:
1742 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001743 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001744 break;
1745 case WLAN_CIPHER_SUITE_AES_CMAC:
1746 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001747 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001748 break;
1749 case WLAN_CIPHER_SUITE_CCMP:
1750 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001751 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001752 break;
1753 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001754 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001755 return -EINVAL;
1756 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001757 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001758 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001759 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001760 }
1761 return err;
1762}
1763
1764static s32
1765brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1766 u8 key_idx, bool pairwise, const u8 *mac_addr,
1767 struct key_params *params)
1768{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001769 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770 struct brcmf_wsec_key key;
1771 s32 val;
1772 s32 wsec;
1773 s32 err = 0;
1774 u8 keybuf[8];
1775
Arend van Sprield96b8012012-12-05 15:26:02 +01001776 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001777 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001778 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001779 return -EIO;
1780
1781 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001782 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001783 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1784 }
1785 memset(&key, 0, sizeof(key));
1786
1787 key.len = (u32) params->key_len;
1788 key.index = (u32) key_idx;
1789
1790 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001791 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001792 err = -EINVAL;
1793 goto done;
1794 }
1795 memcpy(key.data, params->key, key.len);
1796
1797 key.flags = BRCMF_PRIMARY_KEY;
1798 switch (params->cipher) {
1799 case WLAN_CIPHER_SUITE_WEP40:
1800 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001801 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001802 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001803 break;
1804 case WLAN_CIPHER_SUITE_WEP104:
1805 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001806 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001807 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001808 break;
1809 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001810 if (ifp->vif->mode != WL_MODE_AP) {
Arend van Spriel16886732012-12-05 15:26:04 +01001811 brcmf_dbg(CONN, "Swapping key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02001812 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1813 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1814 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1815 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001816 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001817 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001818 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001819 break;
1820 case WLAN_CIPHER_SUITE_AES_CMAC:
1821 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001822 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001823 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001824 break;
1825 case WLAN_CIPHER_SUITE_CCMP:
1826 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001827 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001828 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001829 break;
1830 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001831 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001832 err = -EINVAL;
1833 goto done;
1834 }
1835
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001836 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001837 if (err)
1838 goto done;
1839
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001840 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001841 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001842 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001843 goto done;
1844 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001845 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001846 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001847 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001848 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001849 goto done;
1850 }
1851
Arend van Spriel5b435de2011-10-05 13:19:03 +02001852done:
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_del_key(struct wiphy *wiphy, struct net_device *ndev,
1859 u8 key_idx, bool pairwise, const u8 *mac_addr)
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 struct brcmf_wsec_key key;
1863 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001864
Arend van Sprield96b8012012-12-05 15:26:02 +01001865 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001866 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001867 return -EIO;
1868
Hante Meuleman256c3742012-11-05 16:22:28 -08001869 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
1870 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01001871 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08001872 return -EINVAL;
1873 }
1874
Arend van Spriel5b435de2011-10-05 13:19:03 +02001875 memset(&key, 0, sizeof(key));
1876
1877 key.index = (u32) key_idx;
1878 key.flags = BRCMF_PRIMARY_KEY;
1879 key.algo = CRYPTO_ALGO_OFF;
1880
Arend van Spriel16886732012-12-05 15:26:04 +01001881 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001882
1883 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001884 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001885
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_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1892 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
1893 void (*callback) (void *cookie, struct key_params * params))
1894{
1895 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001896 struct brcmf_if *ifp = netdev_priv(ndev);
1897 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001898 struct brcmf_cfg80211_security *sec;
1899 s32 wsec;
1900 s32 err = 0;
1901
Arend van Sprield96b8012012-12-05 15:26:02 +01001902 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001903 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001904 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001905 return -EIO;
1906
1907 memset(&params, 0, sizeof(params));
1908
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001909 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001911 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001912 /* Ignore this error, may happen during DISASSOC */
1913 err = -EAGAIN;
1914 goto done;
1915 }
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001916 switch (wsec & ~SES_OW_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001917 case WEP_ENABLED:
Arend van Spriel06bb1232012-09-27 14:17:56 +02001918 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001919 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1920 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01001921 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001922 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1923 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01001924 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001925 }
1926 break;
1927 case TKIP_ENABLED:
1928 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001929 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001930 break;
1931 case AES_ENABLED:
1932 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01001933 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001934 break;
1935 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001936 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001937 err = -EINVAL;
1938 goto done;
1939 }
1940 callback(cookie, &params);
1941
1942done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001943 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001944 return err;
1945}
1946
1947static s32
1948brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
1949 struct net_device *ndev, u8 key_idx)
1950{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001951 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001952
1953 return -EOPNOTSUPP;
1954}
1955
1956static s32
1957brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02001958 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001959{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001960 struct brcmf_if *ifp = netdev_priv(ndev);
1961 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001962 struct brcmf_scb_val_le scb_val;
1963 int rssi;
1964 s32 rate;
1965 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02001966 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001967 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968
Arend van Sprield96b8012012-12-05 15:26:02 +01001969 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07001970 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001971 return -EIO;
1972
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001973 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001974 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001975 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07001976 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001977 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02001978 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001979 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001980 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02001981 }
Hante Meuleman1a873342012-09-27 14:17:54 +02001982 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001983 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
1984 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001985 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001986 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02001987 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001988 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
1989 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001990 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001991 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001992 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
1993 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02001994 err = -ENOENT;
1995 goto done;
1996 }
1997 /* Report the current tx rate */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001998 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02001999 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002000 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002001 goto done;
2002 } else {
2003 sinfo->filled |= STATION_INFO_TX_BITRATE;
2004 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01002005 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02002006 }
2007
Arend van Sprielc1179032012-10-22 13:55:33 -07002008 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2009 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002010 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002011 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2012 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002013 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002014 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002015 goto done;
2016 } else {
2017 rssi = le32_to_cpu(scb_val.val);
2018 sinfo->filled |= STATION_INFO_SIGNAL;
2019 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002020 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002021 }
2022 }
2023 } else
2024 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002025done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002026 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002027 return err;
2028}
2029
2030static s32
2031brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2032 bool enabled, s32 timeout)
2033{
2034 s32 pm;
2035 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002036 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002037 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002038
Arend van Sprield96b8012012-12-05 15:26:02 +01002039 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002040
2041 /*
2042 * Powersave enable/disable request is coming from the
2043 * cfg80211 even before the interface is up. In that
2044 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002045 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002046 * FW later while initializing the dongle
2047 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002048 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002049 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002050
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002051 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002052 goto done;
2053 }
2054
2055 pm = enabled ? PM_FAST : PM_OFF;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002056 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057
Arend van Sprielc1179032012-10-22 13:55:33 -07002058 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002059 if (err) {
2060 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002061 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002062 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002063 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064 }
2065done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002066 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002067 return err;
2068}
2069
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002070static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002071 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002073 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002074 struct ieee80211_channel *notify_channel;
2075 struct cfg80211_bss *bss;
2076 struct ieee80211_supported_band *band;
2077 s32 err = 0;
2078 u16 channel;
2079 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 u16 notify_capability;
2081 u16 notify_interval;
2082 u8 *notify_ie;
2083 size_t notify_ielen;
2084 s32 notify_signal;
2085
2086 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002087 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002088 return 0;
2089 }
2090
2091 channel = bi->ctl_ch ? bi->ctl_ch :
2092 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2093
2094 if (channel <= CH_MAX_2G_CHANNEL)
2095 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2096 else
2097 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2098
2099 freq = ieee80211_channel_to_frequency(channel, band->band);
2100 notify_channel = ieee80211_get_channel(wiphy, freq);
2101
Arend van Spriel5b435de2011-10-05 13:19:03 +02002102 notify_capability = le16_to_cpu(bi->capability);
2103 notify_interval = le16_to_cpu(bi->beacon_period);
2104 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2105 notify_ielen = le32_to_cpu(bi->ie_length);
2106 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2107
Arend van Spriel16886732012-12-05 15:26:04 +01002108 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2109 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2110 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2111 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2112 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002113
2114 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002115 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002116 notify_ielen, notify_signal, GFP_KERNEL);
2117
Franky Line78946e2011-11-10 20:30:34 +01002118 if (!bss)
2119 return -ENOMEM;
2120
2121 cfg80211_put_bss(bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002122
2123 return err;
2124}
2125
Roland Vossen6f09be02011-10-18 14:03:02 +02002126static struct brcmf_bss_info_le *
2127next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2128{
2129 if (bss == NULL)
2130 return list->bss_info_le;
2131 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2132 le32_to_cpu(bss->length));
2133}
2134
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002135static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136{
2137 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002138 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002139 s32 err = 0;
2140 int i;
2141
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002142 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002143 if (bss_list->count != 0 &&
2144 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002145 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2146 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147 return -EOPNOTSUPP;
2148 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002149 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002150 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002151 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002152 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002153 if (err)
2154 break;
2155 }
2156 return err;
2157}
2158
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002159static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002160 struct net_device *ndev, const u8 *bssid)
2161{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002162 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002163 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002164 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002165 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002166 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002167 u8 *buf = NULL;
2168 s32 err = 0;
2169 u16 channel;
2170 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002171 u16 notify_capability;
2172 u16 notify_interval;
2173 u8 *notify_ie;
2174 size_t notify_ielen;
2175 s32 notify_signal;
2176
Arend van Sprield96b8012012-12-05 15:26:02 +01002177 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002178
2179 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2180 if (buf == NULL) {
2181 err = -ENOMEM;
2182 goto CleanUp;
2183 }
2184
2185 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2186
Arend van Sprielac24be62012-10-22 10:36:23 -07002187 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2188 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002190 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002191 goto CleanUp;
2192 }
2193
Roland Vossend34bf642011-10-18 14:03:01 +02002194 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002195
2196 channel = bi->ctl_ch ? bi->ctl_ch :
2197 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2198
2199 if (channel <= CH_MAX_2G_CHANNEL)
2200 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2201 else
2202 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2203
2204 freq = ieee80211_channel_to_frequency(channel, band->band);
2205 notify_channel = ieee80211_get_channel(wiphy, freq);
2206
Arend van Spriel5b435de2011-10-05 13:19:03 +02002207 notify_capability = le16_to_cpu(bi->capability);
2208 notify_interval = le16_to_cpu(bi->beacon_period);
2209 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2210 notify_ielen = le32_to_cpu(bi->ie_length);
2211 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2212
Arend van Spriel16886732012-12-05 15:26:04 +01002213 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2214 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2215 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2216 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002217
Franky Line78946e2011-11-10 20:30:34 +01002218 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002219 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002220 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2221
Franky Line78946e2011-11-10 20:30:34 +01002222 if (!bss) {
2223 err = -ENOMEM;
2224 goto CleanUp;
2225 }
2226
2227 cfg80211_put_bss(bss);
2228
Arend van Spriel5b435de2011-10-05 13:19:03 +02002229CleanUp:
2230
2231 kfree(buf);
2232
Arend van Sprield96b8012012-12-05 15:26:02 +01002233 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002234
2235 return err;
2236}
2237
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002238static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002239{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002240 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002241}
2242
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002243/*
2244 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2245 * triples, returning a pointer to the substring whose first element
2246 * matches tag
2247 */
Arend van Spriel9f440b72013-02-08 15:53:36 +01002248struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002249{
2250 struct brcmf_tlv *elt;
2251 int totlen;
2252
2253 elt = (struct brcmf_tlv *) buf;
2254 totlen = buflen;
2255
2256 /* find tagged parameter */
Hante Meuleman04012892012-09-27 14:17:49 +02002257 while (totlen >= TLV_HDR_LEN) {
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002258 int len = elt->len;
2259
2260 /* validate remaining totlen */
Hante Meuleman04012892012-09-27 14:17:49 +02002261 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002262 return elt;
2263
Hante Meuleman04012892012-09-27 14:17:49 +02002264 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
2265 totlen -= (len + TLV_HDR_LEN);
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002266 }
2267
2268 return NULL;
2269}
2270
Hante Meuleman1a873342012-09-27 14:17:54 +02002271/* Is any of the tlvs the expected entry? If
2272 * not update the tlvs buffer pointer/length.
2273 */
2274static bool
2275brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
2276 u8 *oui, u32 oui_len, u8 type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277{
Hante Meuleman1a873342012-09-27 14:17:54 +02002278 /* If the contents match the OUI and the type */
2279 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
2280 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
2281 type == ie[TLV_BODY_OFF + oui_len]) {
2282 return true;
2283 }
2284
2285 if (tlvs == NULL)
2286 return false;
2287 /* point to the next ie */
2288 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
2289 /* calculate the length of the rest of the buffer */
2290 *tlvs_len -= (int)(ie - *tlvs);
2291 /* update the pointer to the start of the buffer */
2292 *tlvs = ie;
2293
2294 return false;
2295}
2296
Franky Lin3cb91f52012-10-10 11:13:08 -07002297static struct brcmf_vs_tlv *
Hante Meuleman1a873342012-09-27 14:17:54 +02002298brcmf_find_wpaie(u8 *parse, u32 len)
2299{
2300 struct brcmf_tlv *ie;
2301
Arend van Spriel04b23122012-10-12 12:28:14 +02002302 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002303 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
2304 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
2305 return (struct brcmf_vs_tlv *)ie;
2306 }
2307 return NULL;
2308}
2309
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002310static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002311{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07002312 struct net_device *ndev = cfg_to_ndev(cfg);
2313 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
2314 struct brcmf_if *ifp = netdev_priv(ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002315 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002316 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002317 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002318 u16 beacon_interval;
2319 u8 dtim_period;
2320 size_t ie_len;
2321 u8 *ie;
2322 s32 err = 0;
2323
Arend van Sprield96b8012012-12-05 15:26:02 +01002324 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002325 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002326 return err;
2327
Arend van Spriel06bb1232012-09-27 14:17:56 +02002328 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002329
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002330 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002331 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002332 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002333 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002334 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002335 goto update_bss_info_out;
2336 }
2337
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002338 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2339 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002340 if (err)
2341 goto update_bss_info_out;
2342
2343 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2344 ie_len = le32_to_cpu(bi->ie_length);
2345 beacon_interval = le16_to_cpu(bi->beacon_period);
2346
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002347 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002348 if (tim)
2349 dtim_period = tim->data[1];
2350 else {
2351 /*
2352 * active scan was done so we could not get dtim
2353 * information out of probe response.
2354 * so we speficially query dtim information to dongle.
2355 */
2356 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002357 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002358 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002359 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002360 goto update_bss_info_out;
2361 }
2362 dtim_period = (u8)var;
2363 }
2364
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002366 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002367 return err;
2368}
2369
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002370static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002371{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002372 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002373
Arend van Sprielc1179032012-10-22 13:55:33 -07002374 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002375 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002376 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002377 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002378 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002379 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2380 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002381}
2382
Hante Meulemane756af52012-09-11 21:18:52 +02002383static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2384{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002385 struct brcmf_cfg80211_info *cfg =
2386 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002387 escan_timeout_work);
2388
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002389 brcmf_notify_escan_complete(cfg,
2390 cfg->escan_info.ndev, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002391}
2392
2393static void brcmf_escan_timeout(unsigned long data)
2394{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002395 struct brcmf_cfg80211_info *cfg =
2396 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002397
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002398 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002399 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002400 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002401 }
2402}
2403
2404static s32
2405brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2406 struct brcmf_bss_info_le *bss_info_le)
2407{
2408 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2409 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2410 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2411 bss_info_le->SSID_len == bss->SSID_len &&
2412 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2413 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2414 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002415 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2416 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2417
Hante Meulemane756af52012-09-11 21:18:52 +02002418 /* preserve max RSSI if the measurements are
2419 * both on-channel or both off-channel
2420 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002421 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002422 bss->RSSI = bss_info_le->RSSI;
2423 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2424 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2425 /* preserve the on-channel rssi measurement
2426 * if the new measurement is off channel
2427 */
2428 bss->RSSI = bss_info_le->RSSI;
2429 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2430 }
2431 return 1;
2432 }
2433 return 0;
2434}
2435
2436static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002437brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002438 const struct brcmf_event_msg *e, void *data)
2439{
Arend van Spriel19937322012-11-05 16:22:32 -08002440 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2441 struct net_device *ndev = ifp->ndev;
Hante Meulemane756af52012-09-11 21:18:52 +02002442 s32 status;
2443 s32 err = 0;
2444 struct brcmf_escan_result_le *escan_result_le;
2445 struct brcmf_bss_info_le *bss_info_le;
2446 struct brcmf_bss_info_le *bss = NULL;
2447 u32 bi_length;
2448 struct brcmf_scan_results *list;
2449 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002450 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002451
Arend van Spriel5c36b992012-11-14 18:46:05 -08002452 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002453
Hante Meulemanf07998952012-11-05 16:22:13 -08002454 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002455 brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
2456 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
Hante Meulemane756af52012-09-11 21:18:52 +02002457 return -EPERM;
2458 }
2459
2460 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002461 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002462 escan_result_le = (struct brcmf_escan_result_le *) data;
2463 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002464 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002465 goto exit;
2466 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002467 if (!cfg->scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002468 brcmf_dbg(SCAN, "result without cfg80211 request\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002469 goto exit;
2470 }
2471
2472 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002473 brcmf_err("Invalid bss_count %d: ignoring\n",
2474 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002475 goto exit;
2476 }
2477 bss_info_le = &escan_result_le->bss_info_le;
2478
2479 bi_length = le32_to_cpu(bss_info_le->length);
2480 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2481 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002482 brcmf_err("Invalid bss_info length %d: ignoring\n",
2483 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002484 goto exit;
2485 }
2486
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002487 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002488 BIT(NL80211_IFTYPE_ADHOC))) {
2489 if (le16_to_cpu(bss_info_le->capability) &
2490 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002491 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002492 goto exit;
2493 }
2494 }
2495
2496 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002497 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002498 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002499 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002500 goto exit;
2501 }
2502
2503 for (i = 0; i < list->count; i++) {
2504 bss = bss ? (struct brcmf_bss_info_le *)
2505 ((unsigned char *)bss +
2506 le32_to_cpu(bss->length)) : list->bss_info_le;
2507 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2508 goto exit;
2509 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002510 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002511 bss_info_le, bi_length);
2512 list->version = le32_to_cpu(bss_info_le->version);
2513 list->buflen += bi_length;
2514 list->count++;
2515 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002516 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2517 if (cfg->scan_request) {
2518 cfg->bss_list = (struct brcmf_scan_results *)
2519 cfg->escan_info.escan_buf;
2520 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002521 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002522 brcmf_notify_escan_complete(cfg, ndev, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002523 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002524 } else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002525 brcmf_err("Unexpected scan result 0x%x\n", status);
Hante Meulemane756af52012-09-11 21:18:52 +02002526 }
2527exit:
2528 return err;
2529}
2530
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002531static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002532{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002533 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2534 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002535 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2536 /* Init scan_timeout timer */
2537 init_timer(&cfg->escan_timeout);
2538 cfg->escan_timeout.data = (unsigned long) cfg;
2539 cfg->escan_timeout.function = brcmf_escan_timeout;
2540 INIT_WORK(&cfg->escan_timeout_work,
2541 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002542}
2543
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002544static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002545{
2546 if (ms < 1000 / HZ) {
2547 cond_resched();
2548 mdelay(ms);
2549 } else {
2550 msleep(ms);
2551 }
2552}
2553
2554static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2555{
Arend van Sprield96b8012012-12-05 15:26:02 +01002556 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002557
Arend van Spriel5b435de2011-10-05 13:19:03 +02002558 return 0;
2559}
2560
2561static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2562 struct cfg80211_wowlan *wow)
2563{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002564 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2565 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002566 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002567
Arend van Sprield96b8012012-12-05 15:26:02 +01002568 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002569
2570 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002571 * if the primary net_device is not READY there is nothing
2572 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002573 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002574 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2575 if (!check_vif_up(vif))
2576 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002577
Arend van Spriel7d641072012-10-22 13:55:39 -07002578 list_for_each_entry(vif, &cfg->vif_list, list) {
2579 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2580 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002581 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002582 * While going to suspend if associated with AP disassociate
2583 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002584 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002585 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002586
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002587 /* Make sure WPA_Supplicant receives all the event
2588 * generated due to DISASSOC call to the fw to keep
2589 * the state fw and WPA_Supplicant state consistent
2590 */
2591 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002592 }
2593
Arend van Spriel7d641072012-10-22 13:55:39 -07002594 /* end any scanning */
2595 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002596 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002597
2598 /* Turn off watchdog timer */
Arend van Spriel7d641072012-10-22 13:55:39 -07002599 brcmf_set_mpc(ndev, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002600
Arend van Spriel7d641072012-10-22 13:55:39 -07002601exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002602 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002603 /* clear any scanning activity */
2604 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002605 return 0;
2606}
2607
2608static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002609brcmf_update_pmklist(struct net_device *ndev,
2610 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2611{
2612 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002613 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002614
Arend van Spriel40c8e952011-10-12 20:51:20 +02002615 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2616
Arend van Spriel16886732012-12-05 15:26:04 +01002617 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002618 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002619 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2620 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002621 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002622 brcmf_dbg(CONN, "%02x\n",
2623 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002624 }
2625
2626 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002627 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2628 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002629
2630 return err;
2631}
2632
2633static s32
2634brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2635 struct cfg80211_pmksa *pmksa)
2636{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002637 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002638 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002639 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002640 s32 err = 0;
2641 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002642 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002643
Arend van Sprield96b8012012-12-05 15:26:02 +01002644 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002645 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002646 return -EIO;
2647
Arend van Spriel40c8e952011-10-12 20:51:20 +02002648 pmkid_len = le32_to_cpu(pmkids->npmkid);
2649 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2651 break;
2652 if (i < WL_NUM_PMKIDS_MAX) {
2653 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2654 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002655 if (i == pmkid_len) {
2656 pmkid_len++;
2657 pmkids->npmkid = cpu_to_le32(pmkid_len);
2658 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002659 } else
2660 err = -EINVAL;
2661
Arend van Spriel16886732012-12-05 15:26:04 +01002662 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2663 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002664 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002665 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002666
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002667 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002668
Arend van Sprield96b8012012-12-05 15:26:02 +01002669 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002670 return err;
2671}
2672
2673static s32
2674brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2675 struct cfg80211_pmksa *pmksa)
2676{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002677 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002678 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002679 struct pmkid_list pmkid;
2680 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002681 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002682
Arend van Sprield96b8012012-12-05 15:26:02 +01002683 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002684 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002685 return -EIO;
2686
2687 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2688 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2689
Arend van Spriel16886732012-12-05 15:26:04 +01002690 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2691 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002692 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002693 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002694
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002695 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002696 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002697 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002698 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002699 ETH_ALEN))
2700 break;
2701
Arend van Spriel40c8e952011-10-12 20:51:20 +02002702 if ((pmkid_len > 0)
2703 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002704 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002705 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002706 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002707 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2708 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002709 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002710 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2711 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002712 WLAN_PMKID_LEN);
2713 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002714 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002715 } else
2716 err = -EINVAL;
2717
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002718 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002719
Arend van Sprield96b8012012-12-05 15:26:02 +01002720 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002721 return err;
2722
2723}
2724
2725static s32
2726brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2727{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002728 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002729 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002730 s32 err = 0;
2731
Arend van Sprield96b8012012-12-05 15:26:02 +01002732 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002733 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002734 return -EIO;
2735
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002736 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2737 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002738
Arend van Sprield96b8012012-12-05 15:26:02 +01002739 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002740 return err;
2741
2742}
2743
Arend van Spriele5806072012-09-19 22:21:08 +02002744/*
2745 * PFN result doesn't have all the info which are
2746 * required by the supplicant
2747 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2748 * via wl_inform_single_bss in the required format. Escan does require the
2749 * scan request in the form of cfg80211_scan_request. For timebeing, create
2750 * cfg80211_scan_request one out of the received PNO event.
2751 */
2752static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002753brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002754 const struct brcmf_event_msg *e, void *data)
2755{
Arend van Spriel19937322012-11-05 16:22:32 -08002756 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2757 struct net_device *ndev = ifp->ndev;
Arend van Spriele5806072012-09-19 22:21:08 +02002758 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2759 struct cfg80211_scan_request *request = NULL;
2760 struct cfg80211_ssid *ssid = NULL;
2761 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002762 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002763 int err = 0;
2764 int channel_req = 0;
2765 int band = 0;
2766 struct brcmf_pno_scanresults_le *pfn_result;
2767 u32 result_count;
2768 u32 status;
2769
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002770 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002771
Arend van Spriel5c36b992012-11-14 18:46:05 -08002772 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002773 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002774 return 0;
2775 }
2776
2777 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2778 result_count = le32_to_cpu(pfn_result->count);
2779 status = le32_to_cpu(pfn_result->status);
2780
2781 /*
2782 * PFN event is limited to fit 512 bytes so we may get
2783 * multiple NET_FOUND events. For now place a warning here.
2784 */
2785 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002786 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002787 if (result_count > 0) {
2788 int i;
2789
2790 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002791 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2792 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002793 if (!request || !ssid || !channel) {
2794 err = -ENOMEM;
2795 goto out_err;
2796 }
2797
2798 request->wiphy = wiphy;
2799 data += sizeof(struct brcmf_pno_scanresults_le);
2800 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2801
2802 for (i = 0; i < result_count; i++) {
2803 netinfo = &netinfo_start[i];
2804 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002805 brcmf_err("Invalid netinfo ptr. index: %d\n",
2806 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002807 err = -EINVAL;
2808 goto out_err;
2809 }
2810
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002811 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2812 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002813 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2814 ssid[i].ssid_len = netinfo->SSID_len;
2815 request->n_ssids++;
2816
2817 channel_req = netinfo->channel;
2818 if (channel_req <= CH_MAX_2G_CHANNEL)
2819 band = NL80211_BAND_2GHZ;
2820 else
2821 band = NL80211_BAND_5GHZ;
2822 channel[i].center_freq =
2823 ieee80211_channel_to_frequency(channel_req,
2824 band);
2825 channel[i].band = band;
2826 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2827 request->channels[i] = &channel[i];
2828 request->n_channels++;
2829 }
2830
2831 /* assign parsed ssid array */
2832 if (request->n_ssids)
2833 request->ssids = &ssid[0];
2834
Arend van Sprielc1179032012-10-22 13:55:33 -07002835 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002836 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002837 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002838 }
2839
Arend van Sprielc1179032012-10-22 13:55:33 -07002840 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002841 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002842 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002843 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002844 goto out_err;
2845 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002846 cfg->sched_escan = true;
2847 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002848 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002849 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002850 goto out_err;
2851 }
2852
2853 kfree(ssid);
2854 kfree(channel);
2855 kfree(request);
2856 return 0;
2857
2858out_err:
2859 kfree(ssid);
2860 kfree(channel);
2861 kfree(request);
2862 cfg80211_sched_scan_stopped(wiphy);
2863 return err;
2864}
2865
Arend van Spriele5806072012-09-19 22:21:08 +02002866static int brcmf_dev_pno_clean(struct net_device *ndev)
2867{
Arend van Spriele5806072012-09-19 22:21:08 +02002868 int ret;
2869
2870 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002871 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002872 if (ret == 0) {
2873 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002874 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
2875 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002876 }
2877 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002878 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002879
2880 return ret;
2881}
2882
2883static int brcmf_dev_pno_config(struct net_device *ndev)
2884{
2885 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02002886
2887 memset(&pfn_param, 0, sizeof(pfn_param));
2888 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
2889
2890 /* set extra pno params */
2891 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
2892 pfn_param.repeat = BRCMF_PNO_REPEAT;
2893 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
2894
2895 /* set up pno scan fr */
2896 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
2897
Arend van Sprielac24be62012-10-22 10:36:23 -07002898 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
2899 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02002900}
2901
2902static int
2903brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
2904 struct net_device *ndev,
2905 struct cfg80211_sched_scan_request *request)
2906{
Arend van Sprielc1179032012-10-22 13:55:33 -07002907 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002908 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002909 struct brcmf_pno_net_param_le pfn;
2910 int i;
2911 int ret = 0;
2912
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002913 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
2914 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07002915 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002916 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002917 return -EAGAIN;
2918 }
2919
2920 if (!request || !request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002921 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
2922 request ? request->n_ssids : 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002923 return -EINVAL;
2924 }
2925
2926 if (request->n_ssids > 0) {
2927 for (i = 0; i < request->n_ssids; i++) {
2928 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002929 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
2930 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002931
2932 /*
2933 * match_set ssids is a supert set of n_ssid list,
2934 * so we need not add these set seperately.
2935 */
2936 }
2937 }
2938
2939 if (request->n_match_sets > 0) {
2940 /* clean up everything */
2941 ret = brcmf_dev_pno_clean(ndev);
2942 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002943 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002944 return ret;
2945 }
2946
2947 /* configure pno */
2948 ret = brcmf_dev_pno_config(ndev);
2949 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002950 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002951 return -EINVAL;
2952 }
2953
2954 /* configure each match set */
2955 for (i = 0; i < request->n_match_sets; i++) {
2956 struct cfg80211_ssid *ssid;
2957 u32 ssid_len;
2958
2959 ssid = &request->match_sets[i].ssid;
2960 ssid_len = ssid->ssid_len;
2961
2962 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002963 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002964 continue;
2965 }
2966 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
2967 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
2968 pfn.wsec = cpu_to_le32(0);
2969 pfn.infra = cpu_to_le32(1);
2970 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
2971 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
2972 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07002973 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07002974 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002975 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
2976 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002977 }
2978 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07002979 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002980 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002981 return -EINVAL;
2982 }
2983 } else {
2984 return -EINVAL;
2985 }
2986
2987 return 0;
2988}
2989
2990static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2991 struct net_device *ndev)
2992{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002993 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002994
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002995 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002996 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002997 if (cfg->sched_escan)
2998 brcmf_notify_escan_complete(cfg, ndev, true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02002999 return 0;
3000}
Arend van Spriele5806072012-09-19 22:21:08 +02003001
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003002#ifdef CONFIG_NL80211_TESTMODE
3003static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3004{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003005 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003006 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003007 struct brcmf_dcmd *dcmd = data;
3008 struct sk_buff *reply;
3009 int ret;
3010
Arend van Sprield96b8012012-12-05 15:26:02 +01003011 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3012 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003013
3014 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003015 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3016 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003017 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003018 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3019 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003020 if (ret == 0) {
3021 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3022 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3023 ret = cfg80211_testmode_reply(reply);
3024 }
3025 return ret;
3026}
3027#endif
3028
Hante Meuleman1f170112013-02-06 18:40:38 +01003029static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003030{
3031 s32 err;
3032
3033 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003034 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003035 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003036 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003037 return err;
3038 }
3039 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003040 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003041 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003042 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003043 return err;
3044 }
3045 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003046 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003047 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003048 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003049 return err;
3050 }
3051
3052 return 0;
3053}
3054
3055static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3056{
3057 if (is_rsn_ie)
3058 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3059
3060 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3061}
3062
3063static s32
3064brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003065 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003066{
Arend van Sprielac24be62012-10-22 10:36:23 -07003067 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003068 u32 auth = 0; /* d11 open authentication */
3069 u16 count;
3070 s32 err = 0;
3071 s32 len = 0;
3072 u32 i;
3073 u32 wsec;
3074 u32 pval = 0;
3075 u32 gval = 0;
3076 u32 wpa_auth = 0;
3077 u32 offset;
3078 u8 *data;
3079 u16 rsn_cap;
3080 u32 wme_bss_disable;
3081
Arend van Sprield96b8012012-12-05 15:26:02 +01003082 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003083 if (wpa_ie == NULL)
3084 goto exit;
3085
3086 len = wpa_ie->len + TLV_HDR_LEN;
3087 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003088 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003089 if (!is_rsn_ie)
3090 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003091 else
3092 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003093
3094 /* check for multicast cipher suite */
3095 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3096 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003097 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003098 goto exit;
3099 }
3100
3101 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3102 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003103 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003104 goto exit;
3105 }
3106 offset += TLV_OUI_LEN;
3107
3108 /* pick up multicast cipher */
3109 switch (data[offset]) {
3110 case WPA_CIPHER_NONE:
3111 gval = 0;
3112 break;
3113 case WPA_CIPHER_WEP_40:
3114 case WPA_CIPHER_WEP_104:
3115 gval = WEP_ENABLED;
3116 break;
3117 case WPA_CIPHER_TKIP:
3118 gval = TKIP_ENABLED;
3119 break;
3120 case WPA_CIPHER_AES_CCM:
3121 gval = AES_ENABLED;
3122 break;
3123 default:
3124 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003125 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003126 goto exit;
3127 }
3128
3129 offset++;
3130 /* walk thru unicast cipher list and pick up what we recognize */
3131 count = data[offset] + (data[offset + 1] << 8);
3132 offset += WPA_IE_SUITE_COUNT_LEN;
3133 /* Check for unicast suite(s) */
3134 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3135 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003136 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003137 goto exit;
3138 }
3139 for (i = 0; i < count; i++) {
3140 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3141 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003142 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003143 goto exit;
3144 }
3145 offset += TLV_OUI_LEN;
3146 switch (data[offset]) {
3147 case WPA_CIPHER_NONE:
3148 break;
3149 case WPA_CIPHER_WEP_40:
3150 case WPA_CIPHER_WEP_104:
3151 pval |= WEP_ENABLED;
3152 break;
3153 case WPA_CIPHER_TKIP:
3154 pval |= TKIP_ENABLED;
3155 break;
3156 case WPA_CIPHER_AES_CCM:
3157 pval |= AES_ENABLED;
3158 break;
3159 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003160 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003161 }
3162 offset++;
3163 }
3164 /* walk thru auth management suite list and pick up what we recognize */
3165 count = data[offset] + (data[offset + 1] << 8);
3166 offset += WPA_IE_SUITE_COUNT_LEN;
3167 /* Check for auth key management suite(s) */
3168 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3169 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003170 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003171 goto exit;
3172 }
3173 for (i = 0; i < count; i++) {
3174 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3175 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003176 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003177 goto exit;
3178 }
3179 offset += TLV_OUI_LEN;
3180 switch (data[offset]) {
3181 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003182 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003183 wpa_auth |= WPA_AUTH_NONE;
3184 break;
3185 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003186 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003187 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3188 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3189 break;
3190 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003191 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003192 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3193 (wpa_auth |= WPA_AUTH_PSK);
3194 break;
3195 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003196 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003197 }
3198 offset++;
3199 }
3200
3201 if (is_rsn_ie) {
3202 wme_bss_disable = 1;
3203 if ((offset + RSN_CAP_LEN) <= len) {
3204 rsn_cap = data[offset] + (data[offset + 1] << 8);
3205 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3206 wme_bss_disable = 0;
3207 }
3208 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003209 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003210 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003211 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003212 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003213 goto exit;
3214 }
3215 }
3216 /* FOR WPS , set SES_OW_ENABLED */
3217 wsec = (pval | gval | SES_OW_ENABLED);
3218
3219 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003220 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003221 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003222 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003223 goto exit;
3224 }
3225 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003226 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003227 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003228 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003229 goto exit;
3230 }
3231 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003232 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003233 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003234 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003235 goto exit;
3236 }
3237
3238exit:
3239 return err;
3240}
3241
3242static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003243brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003244 struct parsed_vndr_ies *vndr_ies)
3245{
3246 s32 err = 0;
3247 struct brcmf_vs_tlv *vndrie;
3248 struct brcmf_tlv *ie;
3249 struct parsed_vndr_ie_info *parsed_info;
3250 s32 remaining_len;
3251
3252 remaining_len = (s32)vndr_ie_len;
3253 memset(vndr_ies, 0, sizeof(*vndr_ies));
3254
3255 ie = (struct brcmf_tlv *)vndr_ie_buf;
3256 while (ie) {
3257 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3258 goto next;
3259 vndrie = (struct brcmf_vs_tlv *)ie;
3260 /* len should be bigger than OUI length + one */
3261 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003262 brcmf_err("invalid vndr ie. length is too small %d\n",
3263 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003264 goto next;
3265 }
3266 /* if wpa or wme ie, do not add ie */
3267 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3268 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3269 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003270 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003271 goto next;
3272 }
3273
3274 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3275
3276 /* save vndr ie information */
3277 parsed_info->ie_ptr = (char *)vndrie;
3278 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3279 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3280
3281 vndr_ies->count++;
3282
Arend van Sprield96b8012012-12-05 15:26:02 +01003283 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3284 parsed_info->vndrie.oui[0],
3285 parsed_info->vndrie.oui[1],
3286 parsed_info->vndrie.oui[2],
3287 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003288
Arend van Spriel9f440b72013-02-08 15:53:36 +01003289 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003290 break;
3291next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003292 remaining_len -= (ie->len + TLV_HDR_LEN);
3293 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003294 ie = NULL;
3295 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003296 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3297 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003298 }
3299 return err;
3300}
3301
3302static u32
3303brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3304{
3305
3306 __le32 iecount_le;
3307 __le32 pktflag_le;
3308
3309 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3310 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3311
3312 iecount_le = cpu_to_le32(1);
3313 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3314
3315 pktflag_le = cpu_to_le32(pktflag);
3316 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3317
3318 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3319
3320 return ie_len + VNDR_IE_HDR_SIZE;
3321}
3322
Arend van Spriel1332e262012-11-05 16:22:18 -08003323s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3324 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003325{
Arend van Spriel1332e262012-11-05 16:22:18 -08003326 struct brcmf_if *ifp;
3327 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003328 s32 err = 0;
3329 u8 *iovar_ie_buf;
3330 u8 *curr_ie_buf;
3331 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003332 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003333 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003334 u32 del_add_ie_buf_len = 0;
3335 u32 total_ie_buf_len = 0;
3336 u32 parsed_ie_buf_len = 0;
3337 struct parsed_vndr_ies old_vndr_ies;
3338 struct parsed_vndr_ies new_vndr_ies;
3339 struct parsed_vndr_ie_info *vndrie_info;
3340 s32 i;
3341 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003342 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003343
Arend van Spriel1332e262012-11-05 16:22:18 -08003344 if (!vif)
3345 return -ENODEV;
3346 ifp = vif->ifp;
3347 saved_ie = &vif->saved_ie;
3348
Arend van Sprield96b8012012-12-05 15:26:02 +01003349 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003350 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3351 if (!iovar_ie_buf)
3352 return -ENOMEM;
3353 curr_ie_buf = iovar_ie_buf;
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003354 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003355 switch (pktflag) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01003356 case BRCMF_VNDR_IE_PRBRSP_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003357 mgmt_ie_buf = saved_ie->probe_res_ie;
3358 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3359 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003360 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +01003361 case BRCMF_VNDR_IE_BEACON_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003362 mgmt_ie_buf = saved_ie->beacon_ie;
3363 mgmt_ie_len = &saved_ie->beacon_ie_len;
3364 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003365 break;
3366 default:
3367 err = -EPERM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003368 brcmf_err("not suitable type\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003369 goto exit;
3370 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003371 } else {
Arend van Spriel9f440b72013-02-08 15:53:36 +01003372 switch (pktflag) {
3373 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3374 mgmt_ie_buf = saved_ie->probe_req_ie;
3375 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3376 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3377 break;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003378 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3379 mgmt_ie_buf = saved_ie->probe_res_ie;
3380 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3381 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3382 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +01003383 default:
3384 err = -EPERM;
3385 brcmf_err("not suitable type\n");
3386 goto exit;
3387 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003388 }
3389
3390 if (vndr_ie_len > mgmt_ie_buf_len) {
3391 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003392 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003393 goto exit;
3394 }
3395
3396 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3397 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3398 ptr = curr_ie_buf;
3399 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3400 for (i = 0; i < new_vndr_ies.count; i++) {
3401 vndrie_info = &new_vndr_ies.ie_info[i];
3402 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3403 vndrie_info->ie_len);
3404 parsed_ie_buf_len += vndrie_info->ie_len;
3405 }
3406 }
3407
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003408 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003409 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3410 (memcmp(mgmt_ie_buf, curr_ie_buf,
3411 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003412 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003413 goto exit;
3414 }
3415
3416 /* parse old vndr_ie */
3417 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3418
3419 /* make a command to delete old ie */
3420 for (i = 0; i < old_vndr_ies.count; i++) {
3421 vndrie_info = &old_vndr_ies.ie_info[i];
3422
Arend van Sprield96b8012012-12-05 15:26:02 +01003423 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3424 vndrie_info->vndrie.id,
3425 vndrie_info->vndrie.len,
3426 vndrie_info->vndrie.oui[0],
3427 vndrie_info->vndrie.oui[1],
3428 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003429
3430 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3431 vndrie_info->ie_ptr,
3432 vndrie_info->ie_len,
3433 "del");
3434 curr_ie_buf += del_add_ie_buf_len;
3435 total_ie_buf_len += del_add_ie_buf_len;
3436 }
3437 }
3438
3439 *mgmt_ie_len = 0;
3440 /* Add if there is any extra IE */
3441 if (mgmt_ie_buf && parsed_ie_buf_len) {
3442 ptr = mgmt_ie_buf;
3443
3444 remained_buf_len = mgmt_ie_buf_len;
3445
3446 /* make a command to add new ie */
3447 for (i = 0; i < new_vndr_ies.count; i++) {
3448 vndrie_info = &new_vndr_ies.ie_info[i];
3449
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003450 /* verify remained buf size before copy data */
3451 if (remained_buf_len < (vndrie_info->vndrie.len +
3452 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003453 brcmf_err("no space in mgmt_ie_buf: len left %d",
3454 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003455 break;
3456 }
3457 remained_buf_len -= (vndrie_info->ie_len +
3458 VNDR_IE_VSIE_OFFSET);
3459
Arend van Sprield96b8012012-12-05 15:26:02 +01003460 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3461 vndrie_info->vndrie.id,
3462 vndrie_info->vndrie.len,
3463 vndrie_info->vndrie.oui[0],
3464 vndrie_info->vndrie.oui[1],
3465 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003466
3467 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3468 vndrie_info->ie_ptr,
3469 vndrie_info->ie_len,
3470 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003471
3472 /* save the parsed IE in wl struct */
3473 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3474 vndrie_info->ie_len);
3475 *mgmt_ie_len += vndrie_info->ie_len;
3476
3477 curr_ie_buf += del_add_ie_buf_len;
3478 total_ie_buf_len += del_add_ie_buf_len;
3479 }
3480 }
3481 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003482 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003483 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003484 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003485 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003486 }
3487
3488exit:
3489 kfree(iovar_ie_buf);
3490 return err;
3491}
3492
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01003493s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3494{
3495 s32 pktflags[] = {
3496 BRCMF_VNDR_IE_PRBREQ_FLAG,
3497 BRCMF_VNDR_IE_PRBRSP_FLAG,
3498 BRCMF_VNDR_IE_BEACON_FLAG
3499 };
3500 int i;
3501
3502 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3503 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3504
3505 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3506 return 0;
3507}
3508
Hante Meuleman1a873342012-09-27 14:17:54 +02003509static s32
3510brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3511 struct cfg80211_ap_settings *settings)
3512{
3513 s32 ie_offset;
Arend van Sprielac24be62012-10-22 10:36:23 -07003514 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003515 struct brcmf_tlv *ssid_ie;
3516 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003517 s32 err = -EPERM;
3518 struct brcmf_tlv *rsn_ie;
3519 struct brcmf_vs_tlv *wpa_ie;
3520 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003521
Arend van Sprield96b8012012-12-05 15:26:02 +01003522 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3523 cfg80211_get_chandef_type(&settings->chandef),
3524 settings->beacon_interval,
3525 settings->dtim_period);
3526 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3527 settings->ssid, settings->ssid_len, settings->auth_type,
3528 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003529
Arend van Sprielc1179032012-10-22 13:55:33 -07003530 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003531 brcmf_err("Not in AP creation mode\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003532 return -EPERM;
3533 }
3534
3535 memset(&ssid_le, 0, sizeof(ssid_le));
3536 if (settings->ssid == NULL || settings->ssid_len == 0) {
3537 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3538 ssid_ie = brcmf_parse_tlvs(
3539 (u8 *)&settings->beacon.head[ie_offset],
3540 settings->beacon.head_len - ie_offset,
3541 WLAN_EID_SSID);
3542 if (!ssid_ie)
3543 return -EINVAL;
3544
3545 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3546 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003547 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003548 } else {
3549 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3550 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3551 }
3552
3553 brcmf_set_mpc(ndev, 0);
Arend van Sprielac24be62012-10-22 10:36:23 -07003554 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003555 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003556 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003557 goto exit;
3558 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003559 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003560 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003561 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003562 goto exit;
3563 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003564 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003565 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003566 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003567 goto exit;
3568 }
3569
3570 /* find the RSN_IE */
3571 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3572 settings->beacon.tail_len, WLAN_EID_RSN);
3573
3574 /* find the WPA_IE */
3575 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3576 settings->beacon.tail_len);
3577
Hante Meuleman1a873342012-09-27 14:17:54 +02003578 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003579 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003580 if (wpa_ie != NULL) {
3581 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003582 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003583 if (err < 0)
3584 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003585 } else {
3586 /* RSN IE */
3587 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003588 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003589 if (err < 0)
3590 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003591 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003592 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003593 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003594 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003595 }
3596 /* Set Beacon IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003597 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
Arend van Spriel9f440b72013-02-08 15:53:36 +01003598 BRCMF_VNDR_IE_BEACON_FLAG,
Arend van Spriel1332e262012-11-05 16:22:18 -08003599 settings->beacon.tail,
3600 settings->beacon.tail_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003601 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003602 brcmf_err("Set Beacon IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003603 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003604 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003605
3606 /* Set Probe Response IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003607 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
Arend van Spriel9f440b72013-02-08 15:53:36 +01003608 BRCMF_VNDR_IE_PRBRSP_FLAG,
Arend van Spriel1332e262012-11-05 16:22:18 -08003609 settings->beacon.proberesp_ies,
3610 settings->beacon.proberesp_ies_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003611 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003612 brcmf_err("Set Probe Resp IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003613 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003614 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003615
3616 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003617 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003618 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003619 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003620 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003621 goto exit;
3622 }
3623 }
3624 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003625 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003626 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003627 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003628 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003629 goto exit;
3630 }
3631 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003632 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003633 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003634 brcmf_err("BRCMF_C_UP error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003635 goto exit;
Hante Meuleman2880b862013-02-08 12:06:31 +01003636 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003637 }
3638
3639 memset(&join_params, 0, sizeof(join_params));
3640 /* join parameters starts with ssid */
3641 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3642 /* create softap */
Arend van Sprielac24be62012-10-22 10:36:23 -07003643 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3644 &join_params, sizeof(join_params));
Hante Meuleman1a873342012-09-27 14:17:54 +02003645 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003646 brcmf_err("SET SSID error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003647 goto exit;
3648 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003649 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3650 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003651
3652exit:
3653 if (err)
3654 brcmf_set_mpc(ndev, 1);
3655 return err;
3656}
3657
3658static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3659{
Arend van Sprielc1179032012-10-22 13:55:33 -07003660 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003661 s32 err = -EPERM;
3662
Arend van Sprield96b8012012-12-05 15:26:02 +01003663 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003664
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003665 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003666 /* Due to most likely deauths outstanding we sleep */
3667 /* first to make sure they get processed by fw. */
3668 msleep(400);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003669 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003670 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003671 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003672 goto exit;
3673 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003674 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003675 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003676 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003677 goto exit;
3678 }
3679 brcmf_set_mpc(ndev, 1);
Arend van Sprielc1179032012-10-22 13:55:33 -07003680 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3681 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003682 }
3683exit:
3684 return err;
3685}
3686
3687static int
3688brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3689 u8 *mac)
3690{
3691 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003692 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003693 s32 err;
3694
3695 if (!mac)
3696 return -EFAULT;
3697
Arend van Sprield96b8012012-12-05 15:26:02 +01003698 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003699
Arend van Sprielce81e312012-10-22 13:55:37 -07003700 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003701 return -EIO;
3702
3703 memcpy(&scbval.ea, mac, ETH_ALEN);
3704 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003705 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003706 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003707 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003708 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003709
Arend van Sprield96b8012012-12-05 15:26:02 +01003710 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003711 return err;
3712}
3713
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003714
3715static void
3716brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3717 struct wireless_dev *wdev,
3718 u16 frame_type, bool reg)
3719{
3720 struct brcmf_if *ifp = netdev_priv(wdev->netdev);
3721 struct brcmf_cfg80211_vif *vif = ifp->vif;
3722 u16 mgmt_type;
3723
3724 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3725
3726 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
3727 if (reg)
3728 vif->mgmt_rx_reg |= BIT(mgmt_type);
3729 else
3730 vif->mgmt_rx_reg |= ~BIT(mgmt_type);
3731}
3732
3733
3734static int
3735brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3736 struct ieee80211_channel *chan, bool offchan,
3737 unsigned int wait, const u8 *buf, size_t len,
3738 bool no_cck, bool dont_wait_for_ack, u64 *cookie)
3739{
3740 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3741 const struct ieee80211_mgmt *mgmt;
3742 struct brcmf_cfg80211_vif *vif;
3743 s32 err = 0;
3744 s32 ie_offset;
3745 s32 ie_len;
3746
3747 brcmf_dbg(TRACE, "Enter\n");
3748
3749 *cookie = 0;
3750
3751 mgmt = (const struct ieee80211_mgmt *)buf;
3752
3753 if (ieee80211_is_mgmt(mgmt->frame_control)) {
3754 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
3755 /* Right now the only reason to get a probe response */
3756 /* is for p2p listen response from wpa_supplicant. */
3757 /* Unfortunately the wpa_supplicant sends it on the */
3758 /* primary ndev, while dongle wants it on the p2p */
3759 /* vif. Since this is only reason for a probe */
3760 /* response to be sent, the vif is taken from cfg. */
3761 /* If ever desired to send proberesp for non p2p */
3762 /* response then data should be checked for */
3763 /* "DIRECT-". Note in future supplicant will take */
3764 /* dedicated p2p wdev to do this and then this 'hack'*/
3765 /* is not needed anymore. */
3766 ie_offset = DOT11_MGMT_HDR_LEN +
3767 DOT11_BCN_PRB_FIXED_LEN;
3768 ie_len = len - ie_offset;
3769
3770 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
3771 if (vif == NULL) {
3772 brcmf_err("No p2p device available for probe response\n");
3773 err = -ENODEV;
3774 goto exit;
3775 }
3776 err = brcmf_vif_set_mgmt_ie(vif,
3777 BRCMF_VNDR_IE_PRBRSP_FLAG,
3778 &buf[ie_offset],
3779 ie_len);
3780 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
3781 GFP_KERNEL);
3782 goto exit;
3783 }
3784 }
3785 brcmf_dbg(TRACE, "Unhandled, is_mgmt %d, fc=%04x!!!!!\n",
3786 ieee80211_is_mgmt(mgmt->frame_control), mgmt->frame_control);
3787exit:
3788 return err;
3789}
3790
3791
3792static int
3793brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
3794 struct wireless_dev *wdev,
3795 u64 cookie)
3796{
3797 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3798 struct brcmf_cfg80211_vif *vif;
3799 int err = 0;
3800
3801 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
3802
3803 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
3804 if (vif == NULL) {
3805 brcmf_err("No p2p device available for probe response\n");
3806 err = -ENODEV;
3807 goto exit;
3808 }
3809 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
3810exit:
3811 return err;
3812}
3813
3814static s32 brcmf_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
3815 const struct brcmf_event_msg *e,
3816 void *data)
3817{
3818 struct wireless_dev *wdev;
3819 struct brcmf_cfg80211_vif *vif = ifp->vif;
3820 struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
3821 u16 chanspec = be16_to_cpu(rxframe->chanspec);
3822 u8 *mgmt_frame;
3823 u32 mgmt_frame_len;
3824 s32 freq;
3825 u16 mgmt_type;
3826
3827 brcmf_dbg(INFO,
3828 "Enter: event %d reason %d\n", e->event_code, e->reason);
3829
3830 /* Firmware sends us two proberesponses for each idx one. At the */
3831 /* moment only bsscfgidx 0 is passed up to supplicant */
3832 if (e->bsscfgidx)
3833 return 0;
3834
3835 /* Check if wpa_supplicant has registered for this frame */
3836 brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
3837 mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
3838 if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
3839 return 0;
3840
3841 mgmt_frame = (u8 *)(rxframe + 1);
3842 mgmt_frame_len = e->datalen - sizeof(*rxframe);
3843 freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
3844 CHSPEC_IS2G(chanspec) ?
3845 IEEE80211_BAND_2GHZ :
3846 IEEE80211_BAND_5GHZ);
3847 wdev = ifp->ndev->ieee80211_ptr;
3848 cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
3849
3850 brcmf_dbg(INFO,
3851 "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
3852 mgmt_frame_len, e->datalen, chanspec, freq);
3853
3854 return 0;
3855}
3856
3857
Arend van Spriel5b435de2011-10-05 13:19:03 +02003858static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01003859 .add_virtual_intf = brcmf_cfg80211_add_iface,
3860 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003861 .change_virtual_intf = brcmf_cfg80211_change_iface,
3862 .scan = brcmf_cfg80211_scan,
3863 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
3864 .join_ibss = brcmf_cfg80211_join_ibss,
3865 .leave_ibss = brcmf_cfg80211_leave_ibss,
3866 .get_station = brcmf_cfg80211_get_station,
3867 .set_tx_power = brcmf_cfg80211_set_tx_power,
3868 .get_tx_power = brcmf_cfg80211_get_tx_power,
3869 .add_key = brcmf_cfg80211_add_key,
3870 .del_key = brcmf_cfg80211_del_key,
3871 .get_key = brcmf_cfg80211_get_key,
3872 .set_default_key = brcmf_cfg80211_config_default_key,
3873 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
3874 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003875 .connect = brcmf_cfg80211_connect,
3876 .disconnect = brcmf_cfg80211_disconnect,
3877 .suspend = brcmf_cfg80211_suspend,
3878 .resume = brcmf_cfg80211_resume,
3879 .set_pmksa = brcmf_cfg80211_set_pmksa,
3880 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003881 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02003882 .start_ap = brcmf_cfg80211_start_ap,
3883 .stop_ap = brcmf_cfg80211_stop_ap,
3884 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02003885 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
3886 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003887 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
3888 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
3889 .remain_on_channel = brcmf_p2p_remain_on_channel,
3890 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003891#ifdef CONFIG_NL80211_TESTMODE
3892 .testmode_cmd = brcmf_cfg80211_testmode
3893#endif
Arend van Spriel5b435de2011-10-05 13:19:03 +02003894};
3895
Arend van Spriel9f440b72013-02-08 15:53:36 +01003896static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003897{
Arend van Spriel9f440b72013-02-08 15:53:36 +01003898 switch (type) {
3899 case NL80211_IFTYPE_AP_VLAN:
3900 case NL80211_IFTYPE_WDS:
3901 case NL80211_IFTYPE_MONITOR:
3902 case NL80211_IFTYPE_MESH_POINT:
3903 return -ENOTSUPP;
3904 case NL80211_IFTYPE_ADHOC:
3905 return WL_MODE_IBSS;
3906 case NL80211_IFTYPE_STATION:
3907 case NL80211_IFTYPE_P2P_CLIENT:
3908 return WL_MODE_BSS;
3909 case NL80211_IFTYPE_AP:
3910 case NL80211_IFTYPE_P2P_GO:
3911 return WL_MODE_AP;
3912 case NL80211_IFTYPE_P2P_DEVICE:
3913 return WL_MODE_P2P;
3914 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02003915 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01003916 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003917 }
3918
Arend van Spriel9f440b72013-02-08 15:53:36 +01003919 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003920}
3921
Arend van Spriele5806072012-09-19 22:21:08 +02003922static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
3923{
Arend van Spriele5806072012-09-19 22:21:08 +02003924 /* scheduled scan settings */
3925 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
3926 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
3927 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3928 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02003929}
3930
Arend van Spriel9f440b72013-02-08 15:53:36 +01003931static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
3932 {
3933 .max = 1,
3934 .types = BIT(NL80211_IFTYPE_STATION) |
3935 BIT(NL80211_IFTYPE_ADHOC) |
3936 BIT(NL80211_IFTYPE_AP)
3937 },
3938 {
3939 .max = 1,
3940 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
3941 BIT(NL80211_IFTYPE_P2P_GO)
3942 },
3943};
3944static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
3945 {
3946 .max_interfaces = BRCMF_IFACE_MAX_CNT - 1,
3947 .num_different_channels = 1, /* no multi-channel for now */
3948 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
3949 .limits = brcmf_iface_limits
3950 }
3951};
3952
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003953static const struct ieee80211_txrx_stypes
3954brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
3955 [NL80211_IFTYPE_STATION] = {
3956 .tx = 0xffff,
3957 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3958 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3959 },
3960 [NL80211_IFTYPE_P2P_CLIENT] = {
3961 .tx = 0xffff,
3962 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3963 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3964 },
3965 [NL80211_IFTYPE_P2P_GO] = {
3966 .tx = 0xffff,
3967 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
3968 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
3969 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
3970 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
3971 BIT(IEEE80211_STYPE_AUTH >> 4) |
3972 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
3973 BIT(IEEE80211_STYPE_ACTION >> 4)
3974 }
3975};
3976
Arend van Spriel3eacf862012-10-22 13:55:30 -07003977static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003978{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003979 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003980 s32 err = 0;
3981
Arend van Spriel3eacf862012-10-22 13:55:30 -07003982 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
3983 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003984 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07003985 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003986 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003987 set_wiphy_dev(wiphy, phydev);
3988 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01003989 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07003990 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
3991 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3992 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01003993 BIT(NL80211_IFTYPE_AP) |
3994 BIT(NL80211_IFTYPE_P2P_CLIENT) |
3995 BIT(NL80211_IFTYPE_P2P_GO);
3996 wiphy->iface_combinations = brcmf_iface_combos;
3997 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003998 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3999 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
Arend van Spriel5b435de2011-10-05 13:19:03 +02004000 * it as 11a by default.
4001 * This will be updated with
4002 * 11n phy tables in
4003 * "ifconfig up"
4004 * if phy has 11n capability
4005 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07004006 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4007 wiphy->cipher_suites = __wl_cipher_suites;
4008 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004009 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
4010 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
4011 wiphy->mgmt_stypes = brcmf_txrx_stypes;
4012 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004013 brcmf_wiphy_pno_params(wiphy);
4014 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004015 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004016 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004017 wiphy_free(wiphy);
4018 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004019 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004020 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004021}
4022
Arend van Spriel3eacf862012-10-22 13:55:30 -07004023struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01004024 enum nl80211_iftype type,
4025 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004026{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004027 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004028
Arend van Spriel3eacf862012-10-22 13:55:30 -07004029 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4030 return ERR_PTR(-ENOSPC);
4031
Arend van Spriel33a6b152013-02-08 15:53:39 +01004032 brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
Arend van Spriel9f440b72013-02-08 15:53:36 +01004033 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004034 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4035 if (!vif)
4036 return ERR_PTR(-ENOMEM);
4037
4038 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004039 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004040
Arend van Spriel9f440b72013-02-08 15:53:36 +01004041 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004042 vif->pm_block = pm_block;
4043 vif->roam_off = -1;
4044
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004045 brcmf_init_prof(&vif->profile);
4046
Arend van Spriel3eacf862012-10-22 13:55:30 -07004047 list_add_tail(&vif->list, &cfg->vif_list);
4048 cfg->vif_cnt++;
4049 return vif;
4050}
4051
Arend van Spriel9f440b72013-02-08 15:53:36 +01004052void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004053{
4054 struct brcmf_cfg80211_info *cfg;
4055 struct wiphy *wiphy;
4056
4057 wiphy = vif->wdev.wiphy;
4058 cfg = wiphy_priv(wiphy);
4059 list_del(&vif->list);
4060 cfg->vif_cnt--;
4061
4062 kfree(vif);
4063 if (!cfg->vif_cnt) {
4064 wiphy_unregister(wiphy);
4065 wiphy_free(wiphy);
4066 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004067}
4068
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004069static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004070{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004071 u32 event = e->event_code;
4072 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004073
4074 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004075 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004076 return true;
4077 }
4078
4079 return false;
4080}
4081
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004082static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004083{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004084 u32 event = e->event_code;
4085 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004086
4087 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004088 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004089 return true;
4090 }
4091 return false;
4092}
4093
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004094static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004095 const struct brcmf_event_msg *e)
4096{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004097 u32 event = e->event_code;
4098 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004099
4100 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004101 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4102 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004103 return true;
4104 }
4105
4106 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004107 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004108 return true;
4109 }
4110
4111 return false;
4112}
4113
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004114static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004115{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004116 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004117
4118 kfree(conn_info->req_ie);
4119 conn_info->req_ie = NULL;
4120 conn_info->req_ie_len = 0;
4121 kfree(conn_info->resp_ie);
4122 conn_info->resp_ie = NULL;
4123 conn_info->resp_ie_len = 0;
4124}
4125
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004126static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004127{
Arend van Sprielac24be62012-10-22 10:36:23 -07004128 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004129 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004130 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004131 u32 req_len;
4132 u32 resp_len;
4133 s32 err = 0;
4134
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004135 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004136
Arend van Sprielac24be62012-10-22 10:36:23 -07004137 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4138 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004139 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004140 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004141 return err;
4142 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004143 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004144 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004145 req_len = le32_to_cpu(assoc_info->req_len);
4146 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004147 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004148 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004149 cfg->extra_buf,
4150 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004151 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004152 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004153 return err;
4154 }
4155 conn_info->req_ie_len = req_len;
4156 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004157 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004158 GFP_KERNEL);
4159 } else {
4160 conn_info->req_ie_len = 0;
4161 conn_info->req_ie = NULL;
4162 }
4163 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004164 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004165 cfg->extra_buf,
4166 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004167 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004168 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004169 return err;
4170 }
4171 conn_info->resp_ie_len = resp_len;
4172 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004173 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004174 GFP_KERNEL);
4175 } else {
4176 conn_info->resp_ie_len = 0;
4177 conn_info->resp_ie = NULL;
4178 }
Arend van Spriel16886732012-12-05 15:26:04 +01004179 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4180 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004181
4182 return err;
4183}
4184
4185static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004186brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004187 struct net_device *ndev,
4188 const struct brcmf_event_msg *e)
4189{
Arend van Sprielc1179032012-10-22 13:55:33 -07004190 struct brcmf_if *ifp = netdev_priv(ndev);
4191 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004192 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4193 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004194 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004195 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004196 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004197 u32 freq;
4198 s32 err = 0;
4199 u32 target_channel;
Franky Lina180b832012-10-10 11:13:09 -07004200 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004201
Arend van Sprield96b8012012-12-05 15:26:02 +01004202 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004203
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004204 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004205 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004206 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004207
Franky Lina180b832012-10-10 11:13:09 -07004208 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4209 if (buf == NULL) {
4210 err = -ENOMEM;
4211 goto done;
4212 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004213
Franky Lina180b832012-10-10 11:13:09 -07004214 /* data sent to dongle has to be little endian */
4215 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004216 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004217 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004218
4219 if (err)
4220 goto done;
4221
4222 bi = (struct brcmf_bss_info_le *)(buf + 4);
4223 target_channel = bi->ctl_ch ? bi->ctl_ch :
4224 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004225
4226 if (target_channel <= CH_MAX_2G_CHANNEL)
4227 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4228 else
4229 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4230
4231 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4232 notify_channel = ieee80211_get_channel(wiphy, freq);
4233
Franky Lina180b832012-10-10 11:13:09 -07004234done:
4235 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004236 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004237 conn_info->req_ie, conn_info->req_ie_len,
4238 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004239 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004240
Arend van Sprielc1179032012-10-22 13:55:33 -07004241 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004242 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004243 return err;
4244}
4245
4246static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004247brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004248 struct net_device *ndev, const struct brcmf_event_msg *e,
4249 bool completed)
4250{
Arend van Sprielc1179032012-10-22 13:55:33 -07004251 struct brcmf_if *ifp = netdev_priv(ndev);
4252 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004253 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004254 s32 err = 0;
4255
Arend van Sprield96b8012012-12-05 15:26:02 +01004256 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004257
Arend van Sprielc1179032012-10-22 13:55:33 -07004258 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4259 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004260 if (completed) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004261 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004262 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004263 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004264 }
4265 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004266 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004267 conn_info->req_ie,
4268 conn_info->req_ie_len,
4269 conn_info->resp_ie,
4270 conn_info->resp_ie_len,
4271 completed ? WLAN_STATUS_SUCCESS :
4272 WLAN_STATUS_AUTH_TIMEOUT,
4273 GFP_KERNEL);
4274 if (completed)
Arend van Sprielc1179032012-10-22 13:55:33 -07004275 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4276 &ifp->vif->sme_state);
Arend van Spriel16886732012-12-05 15:26:04 +01004277 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4278 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004279 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004280 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004281 return err;
4282}
4283
4284static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004285brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004286 struct net_device *ndev,
4287 const struct brcmf_event_msg *e, void *data)
4288{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004289 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004290 u32 event = e->event_code;
4291 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004292 struct station_info sinfo;
4293
Arend van Spriel16886732012-12-05 15:26:04 +01004294 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004295 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4296 ndev != cfg_to_ndev(cfg)) {
4297 brcmf_dbg(CONN, "AP mode link down\n");
4298 complete(&cfg->vif_disabled);
4299 return 0;
4300 }
Hante Meuleman1a873342012-09-27 14:17:54 +02004301
Hante Meuleman1a873342012-09-27 14:17:54 +02004302 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004303 (reason == BRCMF_E_STATUS_SUCCESS)) {
4304 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004305 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4306 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004307 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004308 return -EINVAL;
4309 }
4310 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004311 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004312 generation++;
4313 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004314 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004315 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4316 (event == BRCMF_E_DEAUTH_IND) ||
4317 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004318 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004319 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004320 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004321}
4322
4323static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004324brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004325 const struct brcmf_event_msg *e, void *data)
4326{
Arend van Spriel19937322012-11-05 16:22:32 -08004327 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4328 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004329 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004330 s32 err = 0;
4331
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004332 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004333 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004334 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004335 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004336 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004337 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004338 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004339 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004340 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4341 &ifp->vif->sme_state);
4342 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4343 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004344 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004345 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004346 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004347 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004348 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004349 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004350 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004351 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004352 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004353 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004354 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004355 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004356 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004357 if (ndev != cfg_to_ndev(cfg))
4358 complete(&cfg->vif_disabled);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004359 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004360 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004361 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4362 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004363 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004364 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004365 }
4366
4367 return err;
4368}
4369
4370static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004371brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004372 const struct brcmf_event_msg *e, void *data)
4373{
Arend van Spriel19937322012-11-05 16:22:32 -08004374 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004375 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004376 u32 event = e->event_code;
4377 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004378
4379 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004380 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004381 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004382 else
Arend van Spriel19937322012-11-05 16:22:32 -08004383 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004384 }
4385
4386 return err;
4387}
4388
4389static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004390brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004391 const struct brcmf_event_msg *e, void *data)
4392{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004393 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004394 enum nl80211_key_type key_type;
4395
4396 if (flags & BRCMF_EVENT_MSG_GROUP)
4397 key_type = NL80211_KEYTYPE_GROUP;
4398 else
4399 key_type = NL80211_KEYTYPE_PAIRWISE;
4400
Arend van Spriel19937322012-11-05 16:22:32 -08004401 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004402 NULL, GFP_KERNEL);
4403
4404 return 0;
4405}
4406
Arend van Sprield3c0b632013-02-08 15:53:37 +01004407static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4408 const struct brcmf_event_msg *e, void *data)
4409{
4410 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4411 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4412 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4413 struct brcmf_cfg80211_vif *vif;
4414
4415 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4416 ifevent->action, ifevent->flags, ifevent->ifidx,
4417 ifevent->bssidx);
4418
4419
4420 mutex_lock(&event->vif_event_lock);
4421 event->action = ifevent->action;
4422 vif = event->vif;
4423
4424 switch (ifevent->action) {
4425 case BRCMF_E_IF_ADD:
4426 /* waiting process may have timed out */
4427 if (!cfg->vif_event.vif)
4428 return -EBADF;
4429
4430 ifp->vif = vif;
4431 vif->ifp = ifp;
4432 vif->wdev.netdev = ifp->ndev;
4433 ifp->ndev->ieee80211_ptr = &vif->wdev;
4434 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4435 mutex_unlock(&event->vif_event_lock);
4436 wake_up(&event->vif_wq);
4437
4438 /* waiting process need to set the netdev name */
4439 wait_for_completion(&event->vif_complete);
4440 return brcmf_net_attach(ifp);
4441
4442 case BRCMF_E_IF_DEL:
4443 ifp->vif = NULL;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004444 mutex_unlock(&event->vif_event_lock);
4445 /* event may not be upon user request */
4446 if (brcmf_cfg80211_vif_event_armed(cfg))
4447 wake_up(&event->vif_wq);
4448 return 0;
4449
4450 default:
4451 mutex_unlock(&event->vif_event_lock);
4452 break;
4453 }
4454 return -EINVAL;
4455}
4456
Arend van Spriel5b435de2011-10-05 13:19:03 +02004457static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4458{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004459 conf->frag_threshold = (u32)-1;
4460 conf->rts_threshold = (u32)-1;
4461 conf->retry_short = (u32)-1;
4462 conf->retry_long = (u32)-1;
4463 conf->tx_power = -1;
4464}
4465
Arend van Spriel5c36b992012-11-14 18:46:05 -08004466static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004467{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004468 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4469 brcmf_notify_connect_status);
4470 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4471 brcmf_notify_connect_status);
4472 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4473 brcmf_notify_connect_status);
4474 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4475 brcmf_notify_connect_status);
4476 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4477 brcmf_notify_connect_status);
4478 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4479 brcmf_notify_connect_status);
4480 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4481 brcmf_notify_roaming_status);
4482 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4483 brcmf_notify_mic_status);
4484 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4485 brcmf_notify_connect_status);
4486 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4487 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004488 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4489 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004490 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
4491 brcmf_notify_rx_mgmt_p2p_probereq);
4492 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4493 brcmf_p2p_notify_listen_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004494}
4495
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004496static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004497{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004498 kfree(cfg->conf);
4499 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004500 kfree(cfg->escan_ioctl_buf);
4501 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004502 kfree(cfg->extra_buf);
4503 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004504 kfree(cfg->pmk_list);
4505 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004506}
4507
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004508static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004509{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004510 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4511 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004512 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004513 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4514 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004515 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004516 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4517 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004518 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004519 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4520 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004521 goto init_priv_mem_out;
4522
4523 return 0;
4524
4525init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004526 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004527
4528 return -ENOMEM;
4529}
4530
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004531static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004532{
4533 s32 err = 0;
4534
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004535 cfg->scan_request = NULL;
4536 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004537 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004538 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004539 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004540 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004541 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004542 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004543 if (err)
4544 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004545 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004546 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004547 brcmf_init_escan(cfg);
4548 brcmf_init_conf(cfg->conf);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +01004549 init_completion(&cfg->vif_disabled);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004550 return err;
4551}
4552
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004553static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004554{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004555 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004556 brcmf_abort_scanning(cfg);
4557 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004558}
4559
Arend van Sprield3c0b632013-02-08 15:53:37 +01004560static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4561{
4562 init_waitqueue_head(&event->vif_wq);
4563 init_completion(&event->vif_complete);
4564 mutex_init(&event->vif_event_lock);
4565}
4566
Arend van Sprield9cb2592012-12-05 15:25:54 +01004567struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4568 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004569{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004570 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004571 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004572 struct wiphy *wiphy;
4573 struct brcmf_cfg80211_vif *vif;
4574 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004575 s32 err = 0;
4576
4577 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004578 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004579 return NULL;
4580 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004581
Arend van Spriel3eacf862012-10-22 13:55:30 -07004582 ifp = netdev_priv(ndev);
4583 wiphy = brcmf_setup_wiphy(busdev);
4584 if (IS_ERR(wiphy))
4585 return NULL;
4586
4587 cfg = wiphy_priv(wiphy);
4588 cfg->wiphy = wiphy;
4589 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004590 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004591 INIT_LIST_HEAD(&cfg->vif_list);
4592
Arend van Sprield3c0b632013-02-08 15:53:37 +01004593 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004594 if (IS_ERR(vif)) {
4595 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004596 return NULL;
4597 }
4598
Arend van Sprield3c0b632013-02-08 15:53:37 +01004599 vif->ifp = ifp;
4600 vif->wdev.netdev = ndev;
4601 ndev->ieee80211_ptr = &vif->wdev;
4602 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4603
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004604 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004605 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004606 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004607 goto cfg80211_attach_out;
4608 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004609 brcmf_p2p_attach(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004610
Arend van Spriel3eacf862012-10-22 13:55:30 -07004611 ifp->vif = vif;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004612 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004613
4614cfg80211_attach_out:
Arend van Spriel3eacf862012-10-22 13:55:30 -07004615 brcmf_free_vif(vif);
Hante Meuleman2880b862013-02-08 12:06:31 +01004616 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004617 return NULL;
4618}
4619
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004620void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004621{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004622 struct brcmf_cfg80211_vif *vif;
4623 struct brcmf_cfg80211_vif *tmp;
4624
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004625 wl_deinit_priv(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004626 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4627 brcmf_free_vif(vif);
4628 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004629}
4630
Arend van Spriel5b435de2011-10-05 13:19:03 +02004631static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004632brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004633{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004634 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02004635 __le32 roamtrigger[2];
4636 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02004637
4638 /*
4639 * Setup timeout if Beacons are lost and roam is
4640 * off to report link down
4641 */
4642 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004643 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004644 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004645 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004646 goto dongle_rom_out;
4647 }
4648 }
4649
4650 /*
4651 * Enable/Disable built-in roaming to allow supplicant
4652 * to take care of roaming
4653 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004654 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07004655 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004656 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004657 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004658 goto dongle_rom_out;
4659 }
4660
Arend van Sprielf588bc02011-10-12 20:51:22 +02004661 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4662 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004663 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004664 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004665 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004666 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004667 goto dongle_rom_out;
4668 }
4669
Arend van Sprielf588bc02011-10-12 20:51:22 +02004670 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4671 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004672 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004673 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004674 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004675 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004676 goto dongle_rom_out;
4677 }
4678
4679dongle_rom_out:
4680 return err;
4681}
4682
4683static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004684brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02004685 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004686{
4687 s32 err = 0;
4688
Arend van Sprielac24be62012-10-22 10:36:23 -07004689 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004690 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004691 if (err) {
4692 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004693 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004694 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004695 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004696 goto dongle_scantime_out;
4697 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004698 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004699 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004700 if (err) {
4701 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004702 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004703 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004704 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004705 goto dongle_scantime_out;
4706 }
4707
Arend van Sprielac24be62012-10-22 10:36:23 -07004708 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004709 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004710 if (err) {
4711 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004712 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004713 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004714 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004715 goto dongle_scantime_out;
4716 }
4717
4718dongle_scantime_out:
4719 return err;
4720}
4721
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004722static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004723{
Arend van Sprielac24be62012-10-22 10:36:23 -07004724 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004725 struct wiphy *wiphy;
4726 s32 phy_list;
4727 s8 phy;
4728 s32 err = 0;
4729
Hante Meulemanb87e2c42012-11-14 18:46:23 -08004730 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004731 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004732 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004733 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004734 return err;
4735 }
4736
Hante Meuleman3ba81372012-09-19 22:21:13 +02004737 phy = ((char *)&phy_list)[0];
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004738 brcmf_dbg(INFO, "%c phy\n", phy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004739 if (phy == 'n' || phy == 'a') {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004740 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004741 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4742 }
4743
4744 return err;
4745}
4746
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004747static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004748{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004749 return wl_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004750}
4751
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004752static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004753{
4754 struct net_device *ndev;
4755 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01004756 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004757 s32 power_mode;
4758 s32 err = 0;
4759
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004760 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004761 return err;
4762
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004763 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004764 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01004765 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004766
Hante Meuleman40a23292013-01-02 15:22:51 +01004767 /* make sure RF is ready for work */
4768 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
4769
4770 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
4771 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004772
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004773 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01004774 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004775 if (err)
4776 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004777 brcmf_dbg(INFO, "power save set to %s\n",
4778 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004779
Hante Meuleman40a23292013-01-02 15:22:51 +01004780 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004781 if (err)
4782 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07004783 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
4784 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01004785 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004786 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004787 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004788 if (err)
4789 goto default_conf_out;
4790
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004791 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01004792default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004793
4794 return err;
4795
4796}
4797
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004798static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004799{
Arend van Sprielc1179032012-10-22 13:55:33 -07004800 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004801
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004802 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004803}
4804
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004805static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004806{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004807 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07004808
Arend van Spriel5b435de2011-10-05 13:19:03 +02004809 /*
4810 * While going down, if associated with AP disassociate
4811 * from AP to save power
4812 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004813 if (check_vif_up(ifp->vif)) {
4814 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004815
4816 /* Make sure WPA_Supplicant receives all the event
4817 generated due to DISASSOC call to the fw to keep
4818 the state fw and WPA_Supplicant state consistent
4819 */
4820 brcmf_delay(500);
4821 }
4822
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004823 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07004824 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004825
Arend van Spriel5b435de2011-10-05 13:19:03 +02004826 return 0;
4827}
4828
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004829s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004830{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004831 struct brcmf_if *ifp = netdev_priv(ndev);
4832 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004833 s32 err = 0;
4834
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004835 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004836 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004837 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004838
4839 return err;
4840}
4841
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004842s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004843{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004844 struct brcmf_if *ifp = netdev_priv(ndev);
4845 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004846 s32 err = 0;
4847
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004848 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004849 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004850 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004851
4852 return err;
4853}
4854
Arend van Spriel9f440b72013-02-08 15:53:36 +01004855u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
4856{
4857 struct brcmf_cfg80211_vif *vif;
4858 bool result = 0;
4859
4860 list_for_each_entry(vif, &cfg->vif_list, list) {
4861 if (test_bit(state, &vif->sme_state))
4862 result++;
4863 }
4864 return result;
4865}
Arend van Sprield3c0b632013-02-08 15:53:37 +01004866
4867static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
4868 u8 action)
4869{
4870 u8 evt_action;
4871
4872 mutex_lock(&event->vif_event_lock);
4873 evt_action = event->action;
4874 mutex_unlock(&event->vif_event_lock);
4875 return evt_action == action;
4876}
4877
4878void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
4879 struct brcmf_cfg80211_vif *vif)
4880{
4881 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4882
4883 mutex_lock(&event->vif_event_lock);
4884 event->vif = vif;
4885 event->action = 0;
4886 mutex_unlock(&event->vif_event_lock);
4887}
4888
4889bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
4890{
4891 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4892 bool armed;
4893
4894 mutex_lock(&event->vif_event_lock);
4895 armed = event->vif != NULL;
4896 mutex_unlock(&event->vif_event_lock);
4897
4898 return armed;
4899}
4900int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
4901 u8 action, ulong timeout)
4902{
4903 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4904
4905 return wait_event_timeout(event->vif_wq,
4906 vif_event_equals(event, action), timeout);
4907}
4908
4909void brcmf_cfg80211_vif_complete(struct brcmf_cfg80211_info *cfg)
4910{
4911 complete(&cfg->vif_event.vif_complete);
4912}