blob: 6ab6397219a55b3a796036dbd1a9f163c1078cfd [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
448static
449int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
450{
451 switch (wdev->iftype) {
452 case NL80211_IFTYPE_ADHOC:
453 case NL80211_IFTYPE_STATION:
454 case NL80211_IFTYPE_AP:
455 case NL80211_IFTYPE_AP_VLAN:
456 case NL80211_IFTYPE_WDS:
457 case NL80211_IFTYPE_MONITOR:
458 case NL80211_IFTYPE_MESH_POINT:
459 return -EOPNOTSUPP;
460 case NL80211_IFTYPE_P2P_CLIENT:
461 case NL80211_IFTYPE_P2P_GO:
462 return brcmf_p2p_del_vif(wiphy, wdev);
463 case NL80211_IFTYPE_UNSPECIFIED:
464 case NL80211_IFTYPE_P2P_DEVICE:
465 default:
466 return -EINVAL;
467 }
468 return -EOPNOTSUPP;
469}
470
Arend van Spriel5b435de2011-10-05 13:19:03 +0200471static s32
472brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
473 enum nl80211_iftype type, u32 *flags,
474 struct vif_params *params)
475{
Arend van Sprielc1179032012-10-22 13:55:33 -0700476 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100477 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200478 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200479 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200480 s32 err = 0;
481
Arend van Sprield96b8012012-12-05 15:26:02 +0100482 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200483
484 switch (type) {
485 case NL80211_IFTYPE_MONITOR:
486 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100487 brcmf_err("type (%d) : currently we do not support this type\n",
488 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200489 return -EOPNOTSUPP;
490 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100491 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200492 infra = 0;
493 break;
494 case NL80211_IFTYPE_STATION:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100495 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200496 infra = 1;
497 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200498 case NL80211_IFTYPE_AP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100499 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200500 ap = 1;
501 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200502 default:
503 err = -EINVAL;
504 goto done;
505 }
506
Hante Meuleman1a873342012-09-27 14:17:54 +0200507 if (ap) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100508 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100509 brcmf_dbg(INFO, "IF Type = AP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200510 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100511 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200512 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100513 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200514 err = -EAGAIN;
515 goto done;
516 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100517 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
518 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200519 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200520 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200521
522done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100523 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200524
525 return err;
526}
527
Arend van Spriel5b435de2011-10-05 13:19:03 +0200528static void brcmf_set_mpc(struct net_device *ndev, int mpc)
529{
Arend van Sprielc1179032012-10-22 13:55:33 -0700530 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200531 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200532
Arend van Sprielce81e312012-10-22 13:55:37 -0700533 if (check_vif_up(ifp->vif)) {
Arend van Sprielc1179032012-10-22 13:55:33 -0700534 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200535 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100536 brcmf_err("fail to set mpc\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200537 return;
538 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100539 brcmf_dbg(INFO, "MPC : %d\n", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200540 }
541}
542
Hante Meulemane756af52012-09-11 21:18:52 +0200543static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
544 struct cfg80211_scan_request *request)
545{
546 u32 n_ssids;
547 u32 n_channels;
548 s32 i;
549 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200550 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200551 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200552 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200553
Arend van Sprielba40d162012-10-22 13:55:38 -0700554 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200555 params_le->bss_type = DOT11_BSSTYPE_ANY;
556 params_le->scan_type = 0;
557 params_le->channel_num = 0;
558 params_le->nprobes = cpu_to_le32(-1);
559 params_le->active_time = cpu_to_le32(-1);
560 params_le->passive_time = cpu_to_le32(-1);
561 params_le->home_time = cpu_to_le32(-1);
562 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
563
564 /* if request is null exit so it will be all channel broadcast scan */
565 if (!request)
566 return;
567
568 n_ssids = request->n_ssids;
569 n_channels = request->n_channels;
570 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100571 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
572 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200573 if (n_channels > 0) {
574 for (i = 0; i < n_channels; i++) {
Arend van Spriel6e186162012-10-22 10:36:22 -0700575 chanspec = channel_to_chanspec(request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100576 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
577 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200578 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200579 }
580 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100581 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200582 }
583 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100584 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200585 if (n_ssids > 0) {
586 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
587 n_channels * sizeof(u16);
588 offset = roundup(offset, sizeof(u32));
589 ptr = (char *)params_le + offset;
590 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200591 memset(&ssid_le, 0, sizeof(ssid_le));
592 ssid_le.SSID_len =
593 cpu_to_le32(request->ssids[i].ssid_len);
594 memcpy(ssid_le.SSID, request->ssids[i].ssid,
595 request->ssids[i].ssid_len);
596 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100597 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200598 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100599 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
600 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200601 memcpy(ptr, &ssid_le, sizeof(ssid_le));
602 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200603 }
604 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100605 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200606 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100607 brcmf_dbg(SCAN, "SSID %s len=%d\n",
608 params_le->ssid_le.SSID,
609 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200610 params_le->ssid_le.SSID_len =
611 cpu_to_le32(request->ssids->ssid_len);
612 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
613 request->ssids->ssid_len);
614 }
615 }
616 /* Adding mask to channel numbers */
617 params_le->channel_num =
618 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
619 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
620}
621
622static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200623brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
Hante Meulemane756af52012-09-11 21:18:52 +0200624 struct net_device *ndev,
625 bool aborted, bool fw_abort)
626{
627 struct brcmf_scan_params_le params_le;
628 struct cfg80211_scan_request *scan_request;
629 s32 err = 0;
630
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100631 brcmf_dbg(SCAN, "Enter\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200632
633 /* clear scan request, because the FW abort can cause a second call */
634 /* to this functon and might cause a double cfg80211_scan_done */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200635 scan_request = cfg->scan_request;
636 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200637
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200638 if (timer_pending(&cfg->escan_timeout))
639 del_timer_sync(&cfg->escan_timeout);
Hante Meulemane756af52012-09-11 21:18:52 +0200640
641 if (fw_abort) {
642 /* Do a scan abort to stop the driver's scan engine */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100643 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200644 memset(&params_le, 0, sizeof(params_le));
Arend van Sprielba40d162012-10-22 13:55:38 -0700645 memset(params_le.bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200646 params_le.bss_type = DOT11_BSSTYPE_ANY;
647 params_le.scan_type = 0;
648 params_le.channel_num = cpu_to_le32(1);
649 params_le.nprobes = cpu_to_le32(1);
650 params_le.active_time = cpu_to_le32(-1);
651 params_le.passive_time = cpu_to_le32(-1);
652 params_le.home_time = cpu_to_le32(-1);
653 /* Scan is aborted by setting channel_list[0] to -1 */
654 params_le.channel_list[0] = cpu_to_le16(-1);
655 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielac24be62012-10-22 10:36:23 -0700656 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
657 &params_le, sizeof(params_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200658 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100659 brcmf_err("Scan abort failed\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200660 }
Arend van Spriele5806072012-09-19 22:21:08 +0200661 /*
662 * e-scan can be initiated by scheduled scan
663 * which takes precedence.
664 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200665 if (cfg->sched_escan) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100666 brcmf_dbg(SCAN, "scheduled scan completed\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200667 cfg->sched_escan = false;
Arend van Spriele5806072012-09-19 22:21:08 +0200668 if (!aborted)
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200669 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriele5806072012-09-19 22:21:08 +0200670 brcmf_set_mpc(ndev, 1);
671 } else if (scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100672 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
673 aborted ? "Aborted" : "Done");
Hante Meulemane756af52012-09-11 21:18:52 +0200674 cfg80211_scan_done(scan_request, aborted);
675 brcmf_set_mpc(ndev, 1);
676 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700677 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100678 brcmf_err("Scan complete while device not scanning\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200679 return -EPERM;
680 }
681
682 return err;
683}
684
685static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200686brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
Hante Meulemane756af52012-09-11 21:18:52 +0200687 struct cfg80211_scan_request *request, u16 action)
688{
689 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
690 offsetof(struct brcmf_escan_params_le, params_le);
691 struct brcmf_escan_params_le *params;
692 s32 err = 0;
693
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100694 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200695
696 if (request != NULL) {
697 /* Allocate space for populating ssids in struct */
698 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
699
700 /* Allocate space for populating ssids in struct */
701 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
702 }
703
704 params = kzalloc(params_size, GFP_KERNEL);
705 if (!params) {
706 err = -ENOMEM;
707 goto exit;
708 }
709 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
710 brcmf_escan_prep(&params->params_le, request);
711 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
712 params->action = cpu_to_le16(action);
713 params->sync_id = cpu_to_le16(0x1234);
714
Arend van Sprielac24be62012-10-22 10:36:23 -0700715 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
716 params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200717 if (err) {
718 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100719 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200720 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100721 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200722 }
723
724 kfree(params);
725exit:
726 return err;
727}
728
729static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200730brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Hante Meulemane756af52012-09-11 21:18:52 +0200731 struct net_device *ndev, struct cfg80211_scan_request *request)
732{
733 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700734 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200735 struct brcmf_scan_results *results;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100736 struct escan_info *escan = &cfg->escan_info;
Hante Meulemane756af52012-09-11 21:18:52 +0200737
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100738 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriel9f440b72013-02-08 15:53:36 +0100739 escan->ndev = ndev;
740 escan->wiphy = wiphy;
741 escan->escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700742 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700743 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700744 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200745 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100746 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200747 return err;
748 }
749 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200750 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200751 results->version = 0;
752 results->count = 0;
753 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
754
Arend van Spriel9f440b72013-02-08 15:53:36 +0100755 err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200756 if (err)
757 brcmf_set_mpc(ndev, 1);
758 return err;
759}
760
761static s32
762brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
763 struct cfg80211_scan_request *request,
764 struct cfg80211_ssid *this_ssid)
765{
Arend van Sprielc1179032012-10-22 13:55:33 -0700766 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200767 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Hante Meulemane756af52012-09-11 21:18:52 +0200768 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800769 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700770 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200771 bool escan_req;
772 bool spec_scan;
773 s32 err;
774 u32 SSID_len;
775
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100776 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200777
Arend van Sprielc1179032012-10-22 13:55:33 -0700778 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100779 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200780 return -EAGAIN;
781 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700782 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100783 brcmf_err("Scanning being aborted: status (%lu)\n",
784 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200785 return -EAGAIN;
786 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700787 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100788 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200789 return -EAGAIN;
790 }
791
792 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200793 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200794 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
795
796 escan_req = false;
797 if (request) {
798 /* scan bss */
799 ssids = request->ssids;
800 escan_req = true;
801 } else {
802 /* scan in ibss */
803 /* we don't do escan in ibss */
804 ssids = this_ssid;
805 }
806
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200807 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700808 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200809 if (escan_req) {
Arend van Spriel9f440b72013-02-08 15:53:36 +0100810 cfg->escan_info.run = brcmf_run_escan;
811 err = brcmf_p2p_scan_prep(wiphy, request);
812 if (err)
813 goto scan_out;
814
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200815 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800816 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200817 goto scan_out;
818 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100819 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
820 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200821 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
822 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
823 sr->ssid_le.SSID_len = cpu_to_le32(0);
824 spec_scan = false;
825 if (SSID_len) {
826 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
827 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
828 spec_scan = true;
829 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100830 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200831
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700832 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700833 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700834 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200835 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100836 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200837 goto scan_out;
838 }
839 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700840 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700841 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200842 if (err) {
843 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100844 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
845 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200846 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100847 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200848
849 brcmf_set_mpc(ndev, 1);
850 goto scan_out;
851 }
852 }
853
854 return 0;
855
856scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700857 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200858 if (timer_pending(&cfg->escan_timeout))
859 del_timer_sync(&cfg->escan_timeout);
860 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200861 return err;
862}
863
Arend van Spriel5b435de2011-10-05 13:19:03 +0200864static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700865brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200866{
Johannes Bergfd014282012-06-18 19:17:03 +0200867 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200868 s32 err = 0;
869
Arend van Sprield96b8012012-12-05 15:26:02 +0100870 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200871
Arend van Sprielce81e312012-10-22 13:55:37 -0700872 if (!check_vif_up(container_of(request->wdev,
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700873 struct brcmf_cfg80211_vif, wdev)))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200874 return -EIO;
875
Hante Meulemanf07998952012-11-05 16:22:13 -0800876 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200877
Arend van Spriel5b435de2011-10-05 13:19:03 +0200878 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100879 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200880
Arend van Sprield96b8012012-12-05 15:26:02 +0100881 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200882 return err;
883}
884
885static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
886{
887 s32 err = 0;
888
Arend van Sprielac24be62012-10-22 10:36:23 -0700889 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
890 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200891 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100892 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200893
894 return err;
895}
896
897static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
898{
899 s32 err = 0;
900
Arend van Sprielac24be62012-10-22 10:36:23 -0700901 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
902 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200903 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100904 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200905
906 return err;
907}
908
909static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
910{
911 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -0800912 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200913
Arend van Sprielac24be62012-10-22 10:36:23 -0700914 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200915 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100916 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200917 return err;
918 }
919 return err;
920}
921
922static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
923{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200924 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
925 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700926 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200927 s32 err = 0;
928
Arend van Sprield96b8012012-12-05 15:26:02 +0100929 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -0700930 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200931 return -EIO;
932
933 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200934 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
935 cfg->conf->rts_threshold = wiphy->rts_threshold;
936 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200937 if (!err)
938 goto done;
939 }
940 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200941 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
942 cfg->conf->frag_threshold = wiphy->frag_threshold;
943 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200944 if (!err)
945 goto done;
946 }
947 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200948 && (cfg->conf->retry_long != wiphy->retry_long)) {
949 cfg->conf->retry_long = wiphy->retry_long;
950 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200951 if (!err)
952 goto done;
953 }
954 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200955 && (cfg->conf->retry_short != wiphy->retry_short)) {
956 cfg->conf->retry_short = wiphy->retry_short;
957 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200958 if (!err)
959 goto done;
960 }
961
962done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100963 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200964 return err;
965}
966
Arend van Spriel5b435de2011-10-05 13:19:03 +0200967static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
968{
969 memset(prof, 0, sizeof(*prof));
970}
971
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100972static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200973{
Arend van Spriel5b435de2011-10-05 13:19:03 +0200974 s32 err = 0;
975
Arend van Sprield96b8012012-12-05 15:26:02 +0100976 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200977
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100978 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100979 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100980 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -0700981 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200982 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100983 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100984 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200985 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100986 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +0100987 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200988}
989
990static s32
991brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
992 struct cfg80211_ibss_params *params)
993{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200994 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700995 struct brcmf_if *ifp = netdev_priv(ndev);
996 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200997 struct brcmf_join_params join_params;
998 size_t join_params_size = 0;
999 s32 err = 0;
1000 s32 wsec = 0;
1001 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +01001002 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001003
Arend van Sprield96b8012012-12-05 15:26:02 +01001004 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001005 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001006 return -EIO;
1007
1008 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001009 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001010 else {
Arend van Spriel16886732012-12-05 15:26:04 +01001011 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001012 return -EOPNOTSUPP;
1013 }
1014
Arend van Sprielc1179032012-10-22 13:55:33 -07001015 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001016
1017 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001018 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001019 else
Arend van Spriel16886732012-12-05 15:26:04 +01001020 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001021
Johannes Berg683b6d32012-11-08 21:25:48 +01001022 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001023 brcmf_dbg(CONN, "channel: %d\n",
1024 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001025 else
Arend van Spriel16886732012-12-05 15:26:04 +01001026 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001027
1028 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001029 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001030 else
Arend van Spriel16886732012-12-05 15:26:04 +01001031 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001032
1033 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001034 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001035 else
Arend van Spriel16886732012-12-05 15:26:04 +01001036 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001037
1038 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001039 brcmf_dbg(CONN, "beacon interval: %d\n",
1040 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001041 else
Arend van Spriel16886732012-12-05 15:26:04 +01001042 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001043
1044 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001045 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001046 else
Arend van Spriel16886732012-12-05 15:26:04 +01001047 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001048
1049 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001050 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001051 else
Arend van Spriel16886732012-12-05 15:26:04 +01001052 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001053
1054 /* Configure Privacy for starter */
1055 if (params->privacy)
1056 wsec |= WEP_ENABLED;
1057
Arend van Sprielc1179032012-10-22 13:55:33 -07001058 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001059 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001060 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001061 goto done;
1062 }
1063
1064 /* Configure Beacon Interval for starter */
1065 if (params->beacon_interval)
1066 bcnprd = params->beacon_interval;
1067 else
1068 bcnprd = 100;
1069
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001070 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001071 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001072 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001073 goto done;
1074 }
1075
1076 /* Configure required join parameter */
1077 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1078
1079 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001080 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1081 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1082 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1083 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001084 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001085
1086 /* BSSID */
1087 if (params->bssid) {
1088 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1089 join_params_size = sizeof(join_params.ssid_le) +
1090 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001091 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001092 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001093 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001094 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001095 }
1096
Arend van Spriel5b435de2011-10-05 13:19:03 +02001097 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001098 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001099 u32 target_channel;
1100
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001101 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001102 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001103 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001104 if (params->channel_fixed) {
1105 /* adding chanspec */
Hante Meuleman17012612013-02-06 18:40:44 +01001106 chanspec = channel_to_chanspec(params->chandef.chan);
1107 join_params.params_le.chanspec_list[0] =
1108 cpu_to_le16(chanspec);
1109 join_params.params_le.chanspec_num = cpu_to_le32(1);
1110 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001111 }
1112
1113 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001114 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001115 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001116 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001117 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001118 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001119 goto done;
1120 }
1121 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001122 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001123
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001124 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001125
1126
Arend van Sprielc1179032012-10-22 13:55:33 -07001127 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001128 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001129 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001130 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001131 goto done;
1132 }
1133
1134done:
1135 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001136 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001137 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001138 return err;
1139}
1140
1141static s32
1142brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1143{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001144 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001145 s32 err = 0;
1146
Arend van Sprield96b8012012-12-05 15:26:02 +01001147 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001148 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001149 return -EIO;
1150
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001151 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001152
Arend van Sprield96b8012012-12-05 15:26:02 +01001153 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001154
1155 return err;
1156}
1157
1158static s32 brcmf_set_wpa_version(struct net_device *ndev,
1159 struct cfg80211_connect_params *sme)
1160{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001161 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001162 struct brcmf_cfg80211_security *sec;
1163 s32 val = 0;
1164 s32 err = 0;
1165
1166 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1167 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1168 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1169 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1170 else
1171 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001172 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001173 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001174 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001175 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001176 return err;
1177 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001178 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001179 sec->wpa_versions = sme->crypto.wpa_versions;
1180 return err;
1181}
1182
1183static s32 brcmf_set_auth_type(struct net_device *ndev,
1184 struct cfg80211_connect_params *sme)
1185{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001186 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001187 struct brcmf_cfg80211_security *sec;
1188 s32 val = 0;
1189 s32 err = 0;
1190
1191 switch (sme->auth_type) {
1192 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1193 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001194 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001195 break;
1196 case NL80211_AUTHTYPE_SHARED_KEY:
1197 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001198 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 break;
1200 case NL80211_AUTHTYPE_AUTOMATIC:
1201 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001202 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001203 break;
1204 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001205 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001206 default:
1207 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001208 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001209 break;
1210 }
1211
Arend van Sprielac24be62012-10-22 10:36:23 -07001212 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001213 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001214 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001215 return err;
1216 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001217 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001218 sec->auth_type = sme->auth_type;
1219 return err;
1220}
1221
1222static s32
1223brcmf_set_set_cipher(struct net_device *ndev,
1224 struct cfg80211_connect_params *sme)
1225{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001226 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001227 struct brcmf_cfg80211_security *sec;
1228 s32 pval = 0;
1229 s32 gval = 0;
1230 s32 err = 0;
1231
1232 if (sme->crypto.n_ciphers_pairwise) {
1233 switch (sme->crypto.ciphers_pairwise[0]) {
1234 case WLAN_CIPHER_SUITE_WEP40:
1235 case WLAN_CIPHER_SUITE_WEP104:
1236 pval = WEP_ENABLED;
1237 break;
1238 case WLAN_CIPHER_SUITE_TKIP:
1239 pval = TKIP_ENABLED;
1240 break;
1241 case WLAN_CIPHER_SUITE_CCMP:
1242 pval = AES_ENABLED;
1243 break;
1244 case WLAN_CIPHER_SUITE_AES_CMAC:
1245 pval = AES_ENABLED;
1246 break;
1247 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001248 brcmf_err("invalid cipher pairwise (%d)\n",
1249 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250 return -EINVAL;
1251 }
1252 }
1253 if (sme->crypto.cipher_group) {
1254 switch (sme->crypto.cipher_group) {
1255 case WLAN_CIPHER_SUITE_WEP40:
1256 case WLAN_CIPHER_SUITE_WEP104:
1257 gval = WEP_ENABLED;
1258 break;
1259 case WLAN_CIPHER_SUITE_TKIP:
1260 gval = TKIP_ENABLED;
1261 break;
1262 case WLAN_CIPHER_SUITE_CCMP:
1263 gval = AES_ENABLED;
1264 break;
1265 case WLAN_CIPHER_SUITE_AES_CMAC:
1266 gval = AES_ENABLED;
1267 break;
1268 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001269 brcmf_err("invalid cipher group (%d)\n",
1270 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001271 return -EINVAL;
1272 }
1273 }
1274
Arend van Spriel16886732012-12-05 15:26:04 +01001275 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Arend van Sprielac24be62012-10-22 10:36:23 -07001276 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001277 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001278 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001279 return err;
1280 }
1281
Arend van Spriel06bb1232012-09-27 14:17:56 +02001282 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1284 sec->cipher_group = sme->crypto.cipher_group;
1285
1286 return err;
1287}
1288
1289static s32
1290brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1291{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001292 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001293 struct brcmf_cfg80211_security *sec;
1294 s32 val = 0;
1295 s32 err = 0;
1296
1297 if (sme->crypto.n_akm_suites) {
Arend van Sprielac24be62012-10-22 10:36:23 -07001298 err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
1299 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001300 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001301 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001302 return err;
1303 }
1304 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1305 switch (sme->crypto.akm_suites[0]) {
1306 case WLAN_AKM_SUITE_8021X:
1307 val = WPA_AUTH_UNSPECIFIED;
1308 break;
1309 case WLAN_AKM_SUITE_PSK:
1310 val = WPA_AUTH_PSK;
1311 break;
1312 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001313 brcmf_err("invalid cipher group (%d)\n",
1314 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001315 return -EINVAL;
1316 }
1317 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1318 switch (sme->crypto.akm_suites[0]) {
1319 case WLAN_AKM_SUITE_8021X:
1320 val = WPA2_AUTH_UNSPECIFIED;
1321 break;
1322 case WLAN_AKM_SUITE_PSK:
1323 val = WPA2_AUTH_PSK;
1324 break;
1325 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001326 brcmf_err("invalid cipher group (%d)\n",
1327 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001328 return -EINVAL;
1329 }
1330 }
1331
Arend van Spriel16886732012-12-05 15:26:04 +01001332 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001333 err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
1334 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001335 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001336 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001337 return err;
1338 }
1339 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001340 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001341 sec->wpa_auth = sme->crypto.akm_suites[0];
1342
1343 return err;
1344}
1345
1346static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001347brcmf_set_sharedkey(struct net_device *ndev,
1348 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001349{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001350 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001351 struct brcmf_cfg80211_security *sec;
1352 struct brcmf_wsec_key key;
1353 s32 val;
1354 s32 err = 0;
1355
Arend van Spriel16886732012-12-05 15:26:04 +01001356 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001357
Roland Vossena718e2f2011-10-12 20:51:24 +02001358 if (sme->key_len == 0)
1359 return 0;
1360
Arend van Spriel06bb1232012-09-27 14:17:56 +02001361 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001362 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1363 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001364
1365 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1366 return 0;
1367
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001368 if (!(sec->cipher_pairwise &
1369 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1370 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001371
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001372 memset(&key, 0, sizeof(key));
1373 key.len = (u32) sme->key_len;
1374 key.index = (u32) sme->key_idx;
1375 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001376 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001377 return -EINVAL;
1378 }
1379 memcpy(key.data, sme->key, key.len);
1380 key.flags = BRCMF_PRIMARY_KEY;
1381 switch (sec->cipher_pairwise) {
1382 case WLAN_CIPHER_SUITE_WEP40:
1383 key.algo = CRYPTO_ALGO_WEP1;
1384 break;
1385 case WLAN_CIPHER_SUITE_WEP104:
1386 key.algo = CRYPTO_ALGO_WEP128;
1387 break;
1388 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001389 brcmf_err("Invalid algorithm (%d)\n",
1390 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001391 return -EINVAL;
1392 }
1393 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001394 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1395 key.len, key.index, key.algo);
1396 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001397 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001398 if (err)
1399 return err;
1400
1401 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001402 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001403 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001404 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001405 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001406 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001407 }
1408 return err;
1409}
1410
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001411static
1412enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1413 enum nl80211_auth_type type)
1414{
1415 u32 ci;
1416 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1417 /* shift to ignore chip revision */
1418 ci = brcmf_get_chip_info(ifp) >> 4;
1419 switch (ci) {
1420 case 43236:
1421 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1422 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1423 default:
1424 break;
1425 }
1426 }
1427 return type;
1428}
1429
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430static s32
1431brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001432 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001434 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001435 struct brcmf_if *ifp = netdev_priv(ndev);
1436 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001437 struct ieee80211_channel *chan = sme->channel;
1438 struct brcmf_join_params join_params;
1439 size_t join_params_size;
1440 struct brcmf_ssid ssid;
Hante Meuleman17012612013-02-06 18:40:44 +01001441 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442
1443 s32 err = 0;
1444
Arend van Sprield96b8012012-12-05 15:26:02 +01001445 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001446 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001447 return -EIO;
1448
1449 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001450 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001451 return -EOPNOTSUPP;
1452 }
1453
Arend van Sprielc1179032012-10-22 13:55:33 -07001454 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001455
1456 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001457 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458 ieee80211_frequency_to_channel(chan->center_freq);
Hante Meuleman17012612013-02-06 18:40:44 +01001459 chanspec = channel_to_chanspec(chan);
1460 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1461 cfg->channel, chan->center_freq, chanspec);
1462 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001463 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001464 chanspec = 0;
1465 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001467 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001468
1469 err = brcmf_set_wpa_version(ndev, sme);
1470 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001471 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001472 goto done;
1473 }
1474
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001475 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001476 err = brcmf_set_auth_type(ndev, sme);
1477 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001478 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001479 goto done;
1480 }
1481
1482 err = brcmf_set_set_cipher(ndev, sme);
1483 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001484 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001485 goto done;
1486 }
1487
1488 err = brcmf_set_key_mgmt(ndev, sme);
1489 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001490 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001491 goto done;
1492 }
1493
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001494 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001495 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001496 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001497 goto done;
1498 }
1499
1500 memset(&join_params, 0, sizeof(join_params));
1501 join_params_size = sizeof(join_params.ssid_le);
1502
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001503 profile->ssid.SSID_len = min_t(u32,
1504 sizeof(ssid.SSID), (u32)sme->ssid_len);
1505 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
1506 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1507 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001508
Arend van Sprielba40d162012-10-22 13:55:38 -07001509 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001510
1511 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
Arend van Spriel16886732012-12-05 15:26:04 +01001512 brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
1513 ssid.SSID, ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001514
Hante Meuleman17012612013-02-06 18:40:44 +01001515 if (cfg->channel) {
1516 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1517 join_params.params_le.chanspec_num = cpu_to_le32(1);
1518 join_params_size += sizeof(join_params.params_le);
1519 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001520 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001521 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001522 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001523 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524
1525done:
1526 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001527 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001528 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001529 return err;
1530}
1531
1532static s32
1533brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1534 u16 reason_code)
1535{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001536 struct brcmf_if *ifp = netdev_priv(ndev);
1537 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538 struct brcmf_scb_val_le scbval;
1539 s32 err = 0;
1540
Arend van Sprield96b8012012-12-05 15:26:02 +01001541 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001542 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001543 return -EIO;
1544
Arend van Sprielc1179032012-10-22 13:55:33 -07001545 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001546
Arend van Spriel06bb1232012-09-27 14:17:56 +02001547 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001548 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001549 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001550 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001551 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001552 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001553
Arend van Sprield96b8012012-12-05 15:26:02 +01001554 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001555 return err;
1556}
1557
1558static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001559brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001560 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001561{
1562
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001563 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001564 struct net_device *ndev = cfg_to_ndev(cfg);
1565 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001566 u16 txpwrmw;
1567 s32 err = 0;
1568 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001569 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001570
Arend van Sprield96b8012012-12-05 15:26:02 +01001571 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001572 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001573 return -EIO;
1574
1575 switch (type) {
1576 case NL80211_TX_POWER_AUTOMATIC:
1577 break;
1578 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001579 case NL80211_TX_POWER_FIXED:
1580 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001581 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 err = -EINVAL;
1583 goto done;
1584 }
1585 break;
1586 }
1587 /* Make sure radio is off or on as far as software is concerned */
1588 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001589 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001590 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001591 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001592
1593 if (dbm > 0xffff)
1594 txpwrmw = 0xffff;
1595 else
1596 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001597 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1598 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001600 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001601 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001602
1603done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001604 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001605 return err;
1606}
1607
Johannes Bergc8442112012-10-24 10:17:18 +02001608static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1609 struct wireless_dev *wdev,
1610 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001611{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001612 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001613 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001614 s32 txpwrdbm;
1615 u8 result;
1616 s32 err = 0;
1617
Arend van Sprield96b8012012-12-05 15:26:02 +01001618 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001619 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001620 return -EIO;
1621
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001622 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001623 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001624 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001625 goto done;
1626 }
1627
1628 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001629 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001630
1631done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001632 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001633 return err;
1634}
1635
1636static s32
1637brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1638 u8 key_idx, bool unicast, bool multicast)
1639{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001640 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001641 u32 index;
1642 u32 wsec;
1643 s32 err = 0;
1644
Arend van Sprield96b8012012-12-05 15:26:02 +01001645 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001646 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001647 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001648 return -EIO;
1649
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001650 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001651 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001652 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001653 goto done;
1654 }
1655
1656 if (wsec & WEP_ENABLED) {
1657 /* Just select a new current key */
1658 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001659 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001660 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001661 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001662 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001663 }
1664done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001665 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001666 return err;
1667}
1668
1669static s32
1670brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1671 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1672{
1673 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001674 s32 err = 0;
1675
1676 memset(&key, 0, sizeof(key));
1677 key.index = (u32) key_idx;
1678 /* Instead of bcast for ea address for default wep keys,
1679 driver needs it to be Null */
1680 if (!is_multicast_ether_addr(mac_addr))
1681 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1682 key.len = (u32) params->key_len;
1683 /* check for key index change */
1684 if (key.len == 0) {
1685 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001686 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001687 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001688 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001689 } else {
1690 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001691 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001692 return -EINVAL;
1693 }
1694
Arend van Spriel16886732012-12-05 15:26:04 +01001695 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001696 memcpy(key.data, params->key, key.len);
1697
1698 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1699 u8 keybuf[8];
1700 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1701 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1702 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1703 }
1704
1705 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1706 if (params->seq && params->seq_len == 6) {
1707 /* rx iv */
1708 u8 *ivptr;
1709 ivptr = (u8 *) params->seq;
1710 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1711 (ivptr[3] << 8) | ivptr[2];
1712 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1713 key.iv_initialized = true;
1714 }
1715
1716 switch (params->cipher) {
1717 case WLAN_CIPHER_SUITE_WEP40:
1718 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001719 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001720 break;
1721 case WLAN_CIPHER_SUITE_WEP104:
1722 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001723 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001724 break;
1725 case WLAN_CIPHER_SUITE_TKIP:
1726 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001727 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001728 break;
1729 case WLAN_CIPHER_SUITE_AES_CMAC:
1730 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001731 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001732 break;
1733 case WLAN_CIPHER_SUITE_CCMP:
1734 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001735 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001736 break;
1737 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001738 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001739 return -EINVAL;
1740 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001741 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001742 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001743 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001744 }
1745 return err;
1746}
1747
1748static s32
1749brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1750 u8 key_idx, bool pairwise, const u8 *mac_addr,
1751 struct key_params *params)
1752{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001753 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001754 struct brcmf_wsec_key key;
1755 s32 val;
1756 s32 wsec;
1757 s32 err = 0;
1758 u8 keybuf[8];
1759
Arend van Sprield96b8012012-12-05 15:26:02 +01001760 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001761 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001762 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001763 return -EIO;
1764
1765 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001766 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001767 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1768 }
1769 memset(&key, 0, sizeof(key));
1770
1771 key.len = (u32) params->key_len;
1772 key.index = (u32) key_idx;
1773
1774 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001775 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001776 err = -EINVAL;
1777 goto done;
1778 }
1779 memcpy(key.data, params->key, key.len);
1780
1781 key.flags = BRCMF_PRIMARY_KEY;
1782 switch (params->cipher) {
1783 case WLAN_CIPHER_SUITE_WEP40:
1784 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001785 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001786 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001787 break;
1788 case WLAN_CIPHER_SUITE_WEP104:
1789 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001790 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001791 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001792 break;
1793 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001794 if (ifp->vif->mode != WL_MODE_AP) {
Arend van Spriel16886732012-12-05 15:26:04 +01001795 brcmf_dbg(CONN, "Swapping key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02001796 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1797 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1798 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1799 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001800 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001801 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001802 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001803 break;
1804 case WLAN_CIPHER_SUITE_AES_CMAC:
1805 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001806 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001807 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001808 break;
1809 case WLAN_CIPHER_SUITE_CCMP:
1810 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001811 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001812 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001813 break;
1814 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001815 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001816 err = -EINVAL;
1817 goto done;
1818 }
1819
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001820 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001821 if (err)
1822 goto done;
1823
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001824 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001825 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001826 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001827 goto done;
1828 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001829 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001830 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001831 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001832 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001833 goto done;
1834 }
1835
Arend van Spriel5b435de2011-10-05 13:19:03 +02001836done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001837 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001838 return err;
1839}
1840
1841static s32
1842brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1843 u8 key_idx, bool pairwise, const u8 *mac_addr)
1844{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001845 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001846 struct brcmf_wsec_key key;
1847 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001848
Arend van Sprield96b8012012-12-05 15:26:02 +01001849 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001850 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001851 return -EIO;
1852
Hante Meuleman256c3742012-11-05 16:22:28 -08001853 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
1854 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01001855 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08001856 return -EINVAL;
1857 }
1858
Arend van Spriel5b435de2011-10-05 13:19:03 +02001859 memset(&key, 0, sizeof(key));
1860
1861 key.index = (u32) key_idx;
1862 key.flags = BRCMF_PRIMARY_KEY;
1863 key.algo = CRYPTO_ALGO_OFF;
1864
Arend van Spriel16886732012-12-05 15:26:04 +01001865 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001866
1867 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001868 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001869
Arend van Sprield96b8012012-12-05 15:26:02 +01001870 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001871 return err;
1872}
1873
1874static s32
1875brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1876 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
1877 void (*callback) (void *cookie, struct key_params * params))
1878{
1879 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001880 struct brcmf_if *ifp = netdev_priv(ndev);
1881 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001882 struct brcmf_cfg80211_security *sec;
1883 s32 wsec;
1884 s32 err = 0;
1885
Arend van Sprield96b8012012-12-05 15:26:02 +01001886 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001887 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001888 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001889 return -EIO;
1890
1891 memset(&params, 0, sizeof(params));
1892
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001893 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001894 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001895 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001896 /* Ignore this error, may happen during DISASSOC */
1897 err = -EAGAIN;
1898 goto done;
1899 }
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001900 switch (wsec & ~SES_OW_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001901 case WEP_ENABLED:
Arend van Spriel06bb1232012-09-27 14:17:56 +02001902 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1904 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01001905 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001906 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1907 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01001908 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001909 }
1910 break;
1911 case TKIP_ENABLED:
1912 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001913 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001914 break;
1915 case AES_ENABLED:
1916 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01001917 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001918 break;
1919 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001920 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001921 err = -EINVAL;
1922 goto done;
1923 }
1924 callback(cookie, &params);
1925
1926done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001927 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001928 return err;
1929}
1930
1931static s32
1932brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
1933 struct net_device *ndev, u8 key_idx)
1934{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001935 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001936
1937 return -EOPNOTSUPP;
1938}
1939
1940static s32
1941brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02001942 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001943{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001944 struct brcmf_if *ifp = netdev_priv(ndev);
1945 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001946 struct brcmf_scb_val_le scb_val;
1947 int rssi;
1948 s32 rate;
1949 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02001950 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001951 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001952
Arend van Sprield96b8012012-12-05 15:26:02 +01001953 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07001954 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001955 return -EIO;
1956
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001957 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001958 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001959 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07001960 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001961 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02001962 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001963 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001964 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02001965 }
Hante Meuleman1a873342012-09-27 14:17:54 +02001966 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001967 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
1968 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001969 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001970 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02001971 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001972 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
1973 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001974 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001975 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001976 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
1977 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02001978 err = -ENOENT;
1979 goto done;
1980 }
1981 /* Report the current tx rate */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001982 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02001983 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001984 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001985 goto done;
1986 } else {
1987 sinfo->filled |= STATION_INFO_TX_BITRATE;
1988 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01001989 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02001990 }
1991
Arend van Sprielc1179032012-10-22 13:55:33 -07001992 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
1993 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001994 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07001995 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
1996 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02001997 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001998 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001999 goto done;
2000 } else {
2001 rssi = le32_to_cpu(scb_val.val);
2002 sinfo->filled |= STATION_INFO_SIGNAL;
2003 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01002004 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02002005 }
2006 }
2007 } else
2008 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002009done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002010 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002011 return err;
2012}
2013
2014static s32
2015brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2016 bool enabled, s32 timeout)
2017{
2018 s32 pm;
2019 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002020 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002021 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002022
Arend van Sprield96b8012012-12-05 15:26:02 +01002023 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002024
2025 /*
2026 * Powersave enable/disable request is coming from the
2027 * cfg80211 even before the interface is up. In that
2028 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002029 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002030 * FW later while initializing the dongle
2031 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002032 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002033 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002034
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002035 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002036 goto done;
2037 }
2038
2039 pm = enabled ? PM_FAST : PM_OFF;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01002040 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002041
Arend van Sprielc1179032012-10-22 13:55:33 -07002042 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002043 if (err) {
2044 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002045 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002046 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002047 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002048 }
2049done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002050 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002051 return err;
2052}
2053
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002054static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002055 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002057 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002058 struct ieee80211_channel *notify_channel;
2059 struct cfg80211_bss *bss;
2060 struct ieee80211_supported_band *band;
2061 s32 err = 0;
2062 u16 channel;
2063 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064 u16 notify_capability;
2065 u16 notify_interval;
2066 u8 *notify_ie;
2067 size_t notify_ielen;
2068 s32 notify_signal;
2069
2070 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002071 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002072 return 0;
2073 }
2074
2075 channel = bi->ctl_ch ? bi->ctl_ch :
2076 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2077
2078 if (channel <= CH_MAX_2G_CHANNEL)
2079 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2080 else
2081 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2082
2083 freq = ieee80211_channel_to_frequency(channel, band->band);
2084 notify_channel = ieee80211_get_channel(wiphy, freq);
2085
Arend van Spriel5b435de2011-10-05 13:19:03 +02002086 notify_capability = le16_to_cpu(bi->capability);
2087 notify_interval = le16_to_cpu(bi->beacon_period);
2088 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2089 notify_ielen = le32_to_cpu(bi->ie_length);
2090 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2091
Arend van Spriel16886732012-12-05 15:26:04 +01002092 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2093 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2094 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2095 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2096 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002097
2098 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002099 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 notify_ielen, notify_signal, GFP_KERNEL);
2101
Franky Line78946e2011-11-10 20:30:34 +01002102 if (!bss)
2103 return -ENOMEM;
2104
2105 cfg80211_put_bss(bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002106
2107 return err;
2108}
2109
Roland Vossen6f09be02011-10-18 14:03:02 +02002110static struct brcmf_bss_info_le *
2111next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2112{
2113 if (bss == NULL)
2114 return list->bss_info_le;
2115 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2116 le32_to_cpu(bss->length));
2117}
2118
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002119static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120{
2121 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002122 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123 s32 err = 0;
2124 int i;
2125
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002126 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002127 if (bss_list->count != 0 &&
2128 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002129 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2130 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002131 return -EOPNOTSUPP;
2132 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002133 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002134 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002135 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002136 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002137 if (err)
2138 break;
2139 }
2140 return err;
2141}
2142
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002143static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 struct net_device *ndev, const u8 *bssid)
2145{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002146 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002148 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002150 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002151 u8 *buf = NULL;
2152 s32 err = 0;
2153 u16 channel;
2154 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155 u16 notify_capability;
2156 u16 notify_interval;
2157 u8 *notify_ie;
2158 size_t notify_ielen;
2159 s32 notify_signal;
2160
Arend van Sprield96b8012012-12-05 15:26:02 +01002161 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162
2163 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2164 if (buf == NULL) {
2165 err = -ENOMEM;
2166 goto CleanUp;
2167 }
2168
2169 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2170
Arend van Sprielac24be62012-10-22 10:36:23 -07002171 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2172 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002173 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002174 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002175 goto CleanUp;
2176 }
2177
Roland Vossend34bf642011-10-18 14:03:01 +02002178 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002179
2180 channel = bi->ctl_ch ? bi->ctl_ch :
2181 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2182
2183 if (channel <= CH_MAX_2G_CHANNEL)
2184 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2185 else
2186 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2187
2188 freq = ieee80211_channel_to_frequency(channel, band->band);
2189 notify_channel = ieee80211_get_channel(wiphy, freq);
2190
Arend van Spriel5b435de2011-10-05 13:19:03 +02002191 notify_capability = le16_to_cpu(bi->capability);
2192 notify_interval = le16_to_cpu(bi->beacon_period);
2193 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2194 notify_ielen = le32_to_cpu(bi->ie_length);
2195 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2196
Arend van Spriel16886732012-12-05 15:26:04 +01002197 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2198 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2199 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2200 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201
Franky Line78946e2011-11-10 20:30:34 +01002202 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002203 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002204 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2205
Franky Line78946e2011-11-10 20:30:34 +01002206 if (!bss) {
2207 err = -ENOMEM;
2208 goto CleanUp;
2209 }
2210
2211 cfg80211_put_bss(bss);
2212
Arend van Spriel5b435de2011-10-05 13:19:03 +02002213CleanUp:
2214
2215 kfree(buf);
2216
Arend van Sprield96b8012012-12-05 15:26:02 +01002217 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002218
2219 return err;
2220}
2221
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002222static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002223{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002224 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002225}
2226
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002227/*
2228 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2229 * triples, returning a pointer to the substring whose first element
2230 * matches tag
2231 */
Arend van Spriel9f440b72013-02-08 15:53:36 +01002232struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002233{
2234 struct brcmf_tlv *elt;
2235 int totlen;
2236
2237 elt = (struct brcmf_tlv *) buf;
2238 totlen = buflen;
2239
2240 /* find tagged parameter */
Hante Meuleman04012892012-09-27 14:17:49 +02002241 while (totlen >= TLV_HDR_LEN) {
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002242 int len = elt->len;
2243
2244 /* validate remaining totlen */
Hante Meuleman04012892012-09-27 14:17:49 +02002245 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002246 return elt;
2247
Hante Meuleman04012892012-09-27 14:17:49 +02002248 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
2249 totlen -= (len + TLV_HDR_LEN);
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002250 }
2251
2252 return NULL;
2253}
2254
Hante Meuleman1a873342012-09-27 14:17:54 +02002255/* Is any of the tlvs the expected entry? If
2256 * not update the tlvs buffer pointer/length.
2257 */
2258static bool
2259brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
2260 u8 *oui, u32 oui_len, u8 type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002261{
Hante Meuleman1a873342012-09-27 14:17:54 +02002262 /* If the contents match the OUI and the type */
2263 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
2264 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
2265 type == ie[TLV_BODY_OFF + oui_len]) {
2266 return true;
2267 }
2268
2269 if (tlvs == NULL)
2270 return false;
2271 /* point to the next ie */
2272 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
2273 /* calculate the length of the rest of the buffer */
2274 *tlvs_len -= (int)(ie - *tlvs);
2275 /* update the pointer to the start of the buffer */
2276 *tlvs = ie;
2277
2278 return false;
2279}
2280
Franky Lin3cb91f52012-10-10 11:13:08 -07002281static struct brcmf_vs_tlv *
Hante Meuleman1a873342012-09-27 14:17:54 +02002282brcmf_find_wpaie(u8 *parse, u32 len)
2283{
2284 struct brcmf_tlv *ie;
2285
Arend van Spriel04b23122012-10-12 12:28:14 +02002286 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002287 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
2288 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
2289 return (struct brcmf_vs_tlv *)ie;
2290 }
2291 return NULL;
2292}
2293
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002294static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002295{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07002296 struct net_device *ndev = cfg_to_ndev(cfg);
2297 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
2298 struct brcmf_if *ifp = netdev_priv(ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002299 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002300 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002301 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002302 u16 beacon_interval;
2303 u8 dtim_period;
2304 size_t ie_len;
2305 u8 *ie;
2306 s32 err = 0;
2307
Arend van Sprield96b8012012-12-05 15:26:02 +01002308 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002309 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002310 return err;
2311
Arend van Spriel06bb1232012-09-27 14:17:56 +02002312 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002313
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002314 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002315 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002316 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002317 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002318 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002319 goto update_bss_info_out;
2320 }
2321
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002322 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2323 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002324 if (err)
2325 goto update_bss_info_out;
2326
2327 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2328 ie_len = le32_to_cpu(bi->ie_length);
2329 beacon_interval = le16_to_cpu(bi->beacon_period);
2330
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002331 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002332 if (tim)
2333 dtim_period = tim->data[1];
2334 else {
2335 /*
2336 * active scan was done so we could not get dtim
2337 * information out of probe response.
2338 * so we speficially query dtim information to dongle.
2339 */
2340 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002341 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002342 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002343 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002344 goto update_bss_info_out;
2345 }
2346 dtim_period = (u8)var;
2347 }
2348
Arend van Spriel5b435de2011-10-05 13:19:03 +02002349update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002350 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002351 return err;
2352}
2353
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002354static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002355{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002356 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002357
Arend van Sprielc1179032012-10-22 13:55:33 -07002358 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002359 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002360 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002361 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002362 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002363 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2364 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002365}
2366
Hante Meulemane756af52012-09-11 21:18:52 +02002367static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2368{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002369 struct brcmf_cfg80211_info *cfg =
2370 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002371 escan_timeout_work);
2372
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002373 brcmf_notify_escan_complete(cfg,
2374 cfg->escan_info.ndev, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002375}
2376
2377static void brcmf_escan_timeout(unsigned long data)
2378{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002379 struct brcmf_cfg80211_info *cfg =
2380 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002381
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002382 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002383 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002384 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002385 }
2386}
2387
2388static s32
2389brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2390 struct brcmf_bss_info_le *bss_info_le)
2391{
2392 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2393 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2394 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2395 bss_info_le->SSID_len == bss->SSID_len &&
2396 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2397 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2398 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002399 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2400 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2401
Hante Meulemane756af52012-09-11 21:18:52 +02002402 /* preserve max RSSI if the measurements are
2403 * both on-channel or both off-channel
2404 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002405 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002406 bss->RSSI = bss_info_le->RSSI;
2407 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2408 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2409 /* preserve the on-channel rssi measurement
2410 * if the new measurement is off channel
2411 */
2412 bss->RSSI = bss_info_le->RSSI;
2413 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2414 }
2415 return 1;
2416 }
2417 return 0;
2418}
2419
2420static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002421brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002422 const struct brcmf_event_msg *e, void *data)
2423{
Arend van Spriel19937322012-11-05 16:22:32 -08002424 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2425 struct net_device *ndev = ifp->ndev;
Hante Meulemane756af52012-09-11 21:18:52 +02002426 s32 status;
2427 s32 err = 0;
2428 struct brcmf_escan_result_le *escan_result_le;
2429 struct brcmf_bss_info_le *bss_info_le;
2430 struct brcmf_bss_info_le *bss = NULL;
2431 u32 bi_length;
2432 struct brcmf_scan_results *list;
2433 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002434 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002435
Arend van Spriel5c36b992012-11-14 18:46:05 -08002436 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002437
Hante Meulemanf07998952012-11-05 16:22:13 -08002438 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002439 brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
2440 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
Hante Meulemane756af52012-09-11 21:18:52 +02002441 return -EPERM;
2442 }
2443
2444 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002445 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002446 escan_result_le = (struct brcmf_escan_result_le *) data;
2447 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002448 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002449 goto exit;
2450 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002451 if (!cfg->scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002452 brcmf_dbg(SCAN, "result without cfg80211 request\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002453 goto exit;
2454 }
2455
2456 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002457 brcmf_err("Invalid bss_count %d: ignoring\n",
2458 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002459 goto exit;
2460 }
2461 bss_info_le = &escan_result_le->bss_info_le;
2462
2463 bi_length = le32_to_cpu(bss_info_le->length);
2464 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2465 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002466 brcmf_err("Invalid bss_info length %d: ignoring\n",
2467 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002468 goto exit;
2469 }
2470
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002471 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002472 BIT(NL80211_IFTYPE_ADHOC))) {
2473 if (le16_to_cpu(bss_info_le->capability) &
2474 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002475 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002476 goto exit;
2477 }
2478 }
2479
2480 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002481 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002482 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002483 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002484 goto exit;
2485 }
2486
2487 for (i = 0; i < list->count; i++) {
2488 bss = bss ? (struct brcmf_bss_info_le *)
2489 ((unsigned char *)bss +
2490 le32_to_cpu(bss->length)) : list->bss_info_le;
2491 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2492 goto exit;
2493 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002494 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002495 bss_info_le, bi_length);
2496 list->version = le32_to_cpu(bss_info_le->version);
2497 list->buflen += bi_length;
2498 list->count++;
2499 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002500 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2501 if (cfg->scan_request) {
2502 cfg->bss_list = (struct brcmf_scan_results *)
2503 cfg->escan_info.escan_buf;
2504 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002505 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002506 brcmf_notify_escan_complete(cfg, ndev, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002507 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002508 } else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002509 brcmf_err("Unexpected scan result 0x%x\n", status);
Hante Meulemane756af52012-09-11 21:18:52 +02002510 }
2511exit:
2512 return err;
2513}
2514
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002515static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002516{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002517 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2518 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002519 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2520 /* Init scan_timeout timer */
2521 init_timer(&cfg->escan_timeout);
2522 cfg->escan_timeout.data = (unsigned long) cfg;
2523 cfg->escan_timeout.function = brcmf_escan_timeout;
2524 INIT_WORK(&cfg->escan_timeout_work,
2525 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002526}
2527
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002528static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002529{
2530 if (ms < 1000 / HZ) {
2531 cond_resched();
2532 mdelay(ms);
2533 } else {
2534 msleep(ms);
2535 }
2536}
2537
2538static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2539{
Arend van Sprield96b8012012-12-05 15:26:02 +01002540 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002541
Arend van Spriel5b435de2011-10-05 13:19:03 +02002542 return 0;
2543}
2544
2545static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2546 struct cfg80211_wowlan *wow)
2547{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002548 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2549 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002550 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002551
Arend van Sprield96b8012012-12-05 15:26:02 +01002552 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002553
2554 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002555 * if the primary net_device is not READY there is nothing
2556 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002557 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002558 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2559 if (!check_vif_up(vif))
2560 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002561
Arend van Spriel7d641072012-10-22 13:55:39 -07002562 list_for_each_entry(vif, &cfg->vif_list, list) {
2563 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2564 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002565 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002566 * While going to suspend if associated with AP disassociate
2567 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002568 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002569 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002570
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002571 /* Make sure WPA_Supplicant receives all the event
2572 * generated due to DISASSOC call to the fw to keep
2573 * the state fw and WPA_Supplicant state consistent
2574 */
2575 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002576 }
2577
Arend van Spriel7d641072012-10-22 13:55:39 -07002578 /* end any scanning */
2579 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002580 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002581
2582 /* Turn off watchdog timer */
Arend van Spriel7d641072012-10-22 13:55:39 -07002583 brcmf_set_mpc(ndev, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002584
Arend van Spriel7d641072012-10-22 13:55:39 -07002585exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002586 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002587 /* clear any scanning activity */
2588 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002589 return 0;
2590}
2591
2592static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002593brcmf_update_pmklist(struct net_device *ndev,
2594 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2595{
2596 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002597 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002598
Arend van Spriel40c8e952011-10-12 20:51:20 +02002599 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2600
Arend van Spriel16886732012-12-05 15:26:04 +01002601 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002602 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002603 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2604 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002605 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002606 brcmf_dbg(CONN, "%02x\n",
2607 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002608 }
2609
2610 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002611 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2612 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002613
2614 return err;
2615}
2616
2617static s32
2618brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2619 struct cfg80211_pmksa *pmksa)
2620{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002621 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002622 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002623 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002624 s32 err = 0;
2625 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002626 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002627
Arend van Sprield96b8012012-12-05 15:26:02 +01002628 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002629 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002630 return -EIO;
2631
Arend van Spriel40c8e952011-10-12 20:51:20 +02002632 pmkid_len = le32_to_cpu(pmkids->npmkid);
2633 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002634 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2635 break;
2636 if (i < WL_NUM_PMKIDS_MAX) {
2637 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2638 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002639 if (i == pmkid_len) {
2640 pmkid_len++;
2641 pmkids->npmkid = cpu_to_le32(pmkid_len);
2642 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002643 } else
2644 err = -EINVAL;
2645
Arend van Spriel16886732012-12-05 15:26:04 +01002646 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2647 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002648 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002649 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002651 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002652
Arend van Sprield96b8012012-12-05 15:26:02 +01002653 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002654 return err;
2655}
2656
2657static s32
2658brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2659 struct cfg80211_pmksa *pmksa)
2660{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002661 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002662 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002663 struct pmkid_list pmkid;
2664 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002665 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002666
Arend van Sprield96b8012012-12-05 15:26:02 +01002667 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002668 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002669 return -EIO;
2670
2671 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2672 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2673
Arend van Spriel16886732012-12-05 15:26:04 +01002674 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2675 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002676 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002677 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002678
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002679 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002680 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002681 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002682 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002683 ETH_ALEN))
2684 break;
2685
Arend van Spriel40c8e952011-10-12 20:51:20 +02002686 if ((pmkid_len > 0)
2687 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002688 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002689 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002690 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002691 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2692 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002693 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002694 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2695 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002696 WLAN_PMKID_LEN);
2697 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002698 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002699 } else
2700 err = -EINVAL;
2701
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002702 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002703
Arend van Sprield96b8012012-12-05 15:26:02 +01002704 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002705 return err;
2706
2707}
2708
2709static s32
2710brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2711{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002712 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002713 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002714 s32 err = 0;
2715
Arend van Sprield96b8012012-12-05 15:26:02 +01002716 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002717 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002718 return -EIO;
2719
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002720 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2721 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002722
Arend van Sprield96b8012012-12-05 15:26:02 +01002723 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002724 return err;
2725
2726}
2727
Arend van Spriele5806072012-09-19 22:21:08 +02002728/*
2729 * PFN result doesn't have all the info which are
2730 * required by the supplicant
2731 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2732 * via wl_inform_single_bss in the required format. Escan does require the
2733 * scan request in the form of cfg80211_scan_request. For timebeing, create
2734 * cfg80211_scan_request one out of the received PNO event.
2735 */
2736static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002737brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002738 const struct brcmf_event_msg *e, void *data)
2739{
Arend van Spriel19937322012-11-05 16:22:32 -08002740 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2741 struct net_device *ndev = ifp->ndev;
Arend van Spriele5806072012-09-19 22:21:08 +02002742 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2743 struct cfg80211_scan_request *request = NULL;
2744 struct cfg80211_ssid *ssid = NULL;
2745 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002746 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002747 int err = 0;
2748 int channel_req = 0;
2749 int band = 0;
2750 struct brcmf_pno_scanresults_le *pfn_result;
2751 u32 result_count;
2752 u32 status;
2753
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002754 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002755
Arend van Spriel5c36b992012-11-14 18:46:05 -08002756 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002757 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002758 return 0;
2759 }
2760
2761 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2762 result_count = le32_to_cpu(pfn_result->count);
2763 status = le32_to_cpu(pfn_result->status);
2764
2765 /*
2766 * PFN event is limited to fit 512 bytes so we may get
2767 * multiple NET_FOUND events. For now place a warning here.
2768 */
2769 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002770 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002771 if (result_count > 0) {
2772 int i;
2773
2774 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002775 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2776 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002777 if (!request || !ssid || !channel) {
2778 err = -ENOMEM;
2779 goto out_err;
2780 }
2781
2782 request->wiphy = wiphy;
2783 data += sizeof(struct brcmf_pno_scanresults_le);
2784 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2785
2786 for (i = 0; i < result_count; i++) {
2787 netinfo = &netinfo_start[i];
2788 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002789 brcmf_err("Invalid netinfo ptr. index: %d\n",
2790 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002791 err = -EINVAL;
2792 goto out_err;
2793 }
2794
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002795 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2796 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002797 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2798 ssid[i].ssid_len = netinfo->SSID_len;
2799 request->n_ssids++;
2800
2801 channel_req = netinfo->channel;
2802 if (channel_req <= CH_MAX_2G_CHANNEL)
2803 band = NL80211_BAND_2GHZ;
2804 else
2805 band = NL80211_BAND_5GHZ;
2806 channel[i].center_freq =
2807 ieee80211_channel_to_frequency(channel_req,
2808 band);
2809 channel[i].band = band;
2810 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2811 request->channels[i] = &channel[i];
2812 request->n_channels++;
2813 }
2814
2815 /* assign parsed ssid array */
2816 if (request->n_ssids)
2817 request->ssids = &ssid[0];
2818
Arend van Sprielc1179032012-10-22 13:55:33 -07002819 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002820 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002821 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002822 }
2823
Arend van Sprielc1179032012-10-22 13:55:33 -07002824 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002825 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002826 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002827 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002828 goto out_err;
2829 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002830 cfg->sched_escan = true;
2831 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002832 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002833 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002834 goto out_err;
2835 }
2836
2837 kfree(ssid);
2838 kfree(channel);
2839 kfree(request);
2840 return 0;
2841
2842out_err:
2843 kfree(ssid);
2844 kfree(channel);
2845 kfree(request);
2846 cfg80211_sched_scan_stopped(wiphy);
2847 return err;
2848}
2849
Arend van Spriele5806072012-09-19 22:21:08 +02002850static int brcmf_dev_pno_clean(struct net_device *ndev)
2851{
Arend van Spriele5806072012-09-19 22:21:08 +02002852 int ret;
2853
2854 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002855 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002856 if (ret == 0) {
2857 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002858 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
2859 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002860 }
2861 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002862 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002863
2864 return ret;
2865}
2866
2867static int brcmf_dev_pno_config(struct net_device *ndev)
2868{
2869 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02002870
2871 memset(&pfn_param, 0, sizeof(pfn_param));
2872 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
2873
2874 /* set extra pno params */
2875 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
2876 pfn_param.repeat = BRCMF_PNO_REPEAT;
2877 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
2878
2879 /* set up pno scan fr */
2880 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
2881
Arend van Sprielac24be62012-10-22 10:36:23 -07002882 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
2883 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02002884}
2885
2886static int
2887brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
2888 struct net_device *ndev,
2889 struct cfg80211_sched_scan_request *request)
2890{
Arend van Sprielc1179032012-10-22 13:55:33 -07002891 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002892 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002893 struct brcmf_pno_net_param_le pfn;
2894 int i;
2895 int ret = 0;
2896
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002897 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
2898 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07002899 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002900 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002901 return -EAGAIN;
2902 }
2903
2904 if (!request || !request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002905 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
2906 request ? request->n_ssids : 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002907 return -EINVAL;
2908 }
2909
2910 if (request->n_ssids > 0) {
2911 for (i = 0; i < request->n_ssids; i++) {
2912 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002913 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
2914 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002915
2916 /*
2917 * match_set ssids is a supert set of n_ssid list,
2918 * so we need not add these set seperately.
2919 */
2920 }
2921 }
2922
2923 if (request->n_match_sets > 0) {
2924 /* clean up everything */
2925 ret = brcmf_dev_pno_clean(ndev);
2926 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002927 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002928 return ret;
2929 }
2930
2931 /* configure pno */
2932 ret = brcmf_dev_pno_config(ndev);
2933 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002934 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002935 return -EINVAL;
2936 }
2937
2938 /* configure each match set */
2939 for (i = 0; i < request->n_match_sets; i++) {
2940 struct cfg80211_ssid *ssid;
2941 u32 ssid_len;
2942
2943 ssid = &request->match_sets[i].ssid;
2944 ssid_len = ssid->ssid_len;
2945
2946 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002947 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002948 continue;
2949 }
2950 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
2951 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
2952 pfn.wsec = cpu_to_le32(0);
2953 pfn.infra = cpu_to_le32(1);
2954 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
2955 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
2956 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07002957 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07002958 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002959 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
2960 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002961 }
2962 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07002963 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002964 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002965 return -EINVAL;
2966 }
2967 } else {
2968 return -EINVAL;
2969 }
2970
2971 return 0;
2972}
2973
2974static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2975 struct net_device *ndev)
2976{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002977 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002978
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002979 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002980 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002981 if (cfg->sched_escan)
2982 brcmf_notify_escan_complete(cfg, ndev, true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02002983 return 0;
2984}
Arend van Spriele5806072012-09-19 22:21:08 +02002985
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002986#ifdef CONFIG_NL80211_TESTMODE
2987static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
2988{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002989 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07002990 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002991 struct brcmf_dcmd *dcmd = data;
2992 struct sk_buff *reply;
2993 int ret;
2994
Arend van Sprield96b8012012-12-05 15:26:02 +01002995 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
2996 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07002997
2998 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07002999 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3000 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003001 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003002 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3003 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003004 if (ret == 0) {
3005 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3006 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3007 ret = cfg80211_testmode_reply(reply);
3008 }
3009 return ret;
3010}
3011#endif
3012
Hante Meuleman1f170112013-02-06 18:40:38 +01003013static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02003014{
3015 s32 err;
3016
3017 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003018 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003019 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003020 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003021 return err;
3022 }
3023 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003024 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003025 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003026 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003027 return err;
3028 }
3029 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003030 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003031 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003032 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003033 return err;
3034 }
3035
3036 return 0;
3037}
3038
3039static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3040{
3041 if (is_rsn_ie)
3042 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3043
3044 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3045}
3046
3047static s32
3048brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003049 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003050{
Arend van Sprielac24be62012-10-22 10:36:23 -07003051 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003052 u32 auth = 0; /* d11 open authentication */
3053 u16 count;
3054 s32 err = 0;
3055 s32 len = 0;
3056 u32 i;
3057 u32 wsec;
3058 u32 pval = 0;
3059 u32 gval = 0;
3060 u32 wpa_auth = 0;
3061 u32 offset;
3062 u8 *data;
3063 u16 rsn_cap;
3064 u32 wme_bss_disable;
3065
Arend van Sprield96b8012012-12-05 15:26:02 +01003066 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003067 if (wpa_ie == NULL)
3068 goto exit;
3069
3070 len = wpa_ie->len + TLV_HDR_LEN;
3071 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003072 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003073 if (!is_rsn_ie)
3074 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003075 else
3076 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003077
3078 /* check for multicast cipher suite */
3079 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3080 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003081 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003082 goto exit;
3083 }
3084
3085 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3086 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003087 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003088 goto exit;
3089 }
3090 offset += TLV_OUI_LEN;
3091
3092 /* pick up multicast cipher */
3093 switch (data[offset]) {
3094 case WPA_CIPHER_NONE:
3095 gval = 0;
3096 break;
3097 case WPA_CIPHER_WEP_40:
3098 case WPA_CIPHER_WEP_104:
3099 gval = WEP_ENABLED;
3100 break;
3101 case WPA_CIPHER_TKIP:
3102 gval = TKIP_ENABLED;
3103 break;
3104 case WPA_CIPHER_AES_CCM:
3105 gval = AES_ENABLED;
3106 break;
3107 default:
3108 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003109 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003110 goto exit;
3111 }
3112
3113 offset++;
3114 /* walk thru unicast cipher list and pick up what we recognize */
3115 count = data[offset] + (data[offset + 1] << 8);
3116 offset += WPA_IE_SUITE_COUNT_LEN;
3117 /* Check for unicast suite(s) */
3118 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3119 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003120 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003121 goto exit;
3122 }
3123 for (i = 0; i < count; i++) {
3124 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3125 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003126 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003127 goto exit;
3128 }
3129 offset += TLV_OUI_LEN;
3130 switch (data[offset]) {
3131 case WPA_CIPHER_NONE:
3132 break;
3133 case WPA_CIPHER_WEP_40:
3134 case WPA_CIPHER_WEP_104:
3135 pval |= WEP_ENABLED;
3136 break;
3137 case WPA_CIPHER_TKIP:
3138 pval |= TKIP_ENABLED;
3139 break;
3140 case WPA_CIPHER_AES_CCM:
3141 pval |= AES_ENABLED;
3142 break;
3143 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003144 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003145 }
3146 offset++;
3147 }
3148 /* walk thru auth management suite list and pick up what we recognize */
3149 count = data[offset] + (data[offset + 1] << 8);
3150 offset += WPA_IE_SUITE_COUNT_LEN;
3151 /* Check for auth key management suite(s) */
3152 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3153 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003154 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003155 goto exit;
3156 }
3157 for (i = 0; i < count; i++) {
3158 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3159 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003160 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003161 goto exit;
3162 }
3163 offset += TLV_OUI_LEN;
3164 switch (data[offset]) {
3165 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003166 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003167 wpa_auth |= WPA_AUTH_NONE;
3168 break;
3169 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003170 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003171 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3172 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3173 break;
3174 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003175 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003176 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3177 (wpa_auth |= WPA_AUTH_PSK);
3178 break;
3179 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003180 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003181 }
3182 offset++;
3183 }
3184
3185 if (is_rsn_ie) {
3186 wme_bss_disable = 1;
3187 if ((offset + RSN_CAP_LEN) <= len) {
3188 rsn_cap = data[offset] + (data[offset + 1] << 8);
3189 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3190 wme_bss_disable = 0;
3191 }
3192 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003193 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003194 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003195 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003196 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003197 goto exit;
3198 }
3199 }
3200 /* FOR WPS , set SES_OW_ENABLED */
3201 wsec = (pval | gval | SES_OW_ENABLED);
3202
3203 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003204 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003205 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003206 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003207 goto exit;
3208 }
3209 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003210 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003211 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003212 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003213 goto exit;
3214 }
3215 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003216 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003217 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003218 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003219 goto exit;
3220 }
3221
3222exit:
3223 return err;
3224}
3225
3226static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003227brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003228 struct parsed_vndr_ies *vndr_ies)
3229{
3230 s32 err = 0;
3231 struct brcmf_vs_tlv *vndrie;
3232 struct brcmf_tlv *ie;
3233 struct parsed_vndr_ie_info *parsed_info;
3234 s32 remaining_len;
3235
3236 remaining_len = (s32)vndr_ie_len;
3237 memset(vndr_ies, 0, sizeof(*vndr_ies));
3238
3239 ie = (struct brcmf_tlv *)vndr_ie_buf;
3240 while (ie) {
3241 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3242 goto next;
3243 vndrie = (struct brcmf_vs_tlv *)ie;
3244 /* len should be bigger than OUI length + one */
3245 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003246 brcmf_err("invalid vndr ie. length is too small %d\n",
3247 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003248 goto next;
3249 }
3250 /* if wpa or wme ie, do not add ie */
3251 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3252 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3253 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003254 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003255 goto next;
3256 }
3257
3258 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3259
3260 /* save vndr ie information */
3261 parsed_info->ie_ptr = (char *)vndrie;
3262 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3263 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3264
3265 vndr_ies->count++;
3266
Arend van Sprield96b8012012-12-05 15:26:02 +01003267 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3268 parsed_info->vndrie.oui[0],
3269 parsed_info->vndrie.oui[1],
3270 parsed_info->vndrie.oui[2],
3271 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003272
Arend van Spriel9f440b72013-02-08 15:53:36 +01003273 if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
Hante Meuleman1a873342012-09-27 14:17:54 +02003274 break;
3275next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003276 remaining_len -= (ie->len + TLV_HDR_LEN);
3277 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003278 ie = NULL;
3279 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003280 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3281 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003282 }
3283 return err;
3284}
3285
3286static u32
3287brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3288{
3289
3290 __le32 iecount_le;
3291 __le32 pktflag_le;
3292
3293 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3294 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3295
3296 iecount_le = cpu_to_le32(1);
3297 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3298
3299 pktflag_le = cpu_to_le32(pktflag);
3300 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3301
3302 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3303
3304 return ie_len + VNDR_IE_HDR_SIZE;
3305}
3306
Arend van Spriel1332e262012-11-05 16:22:18 -08003307s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3308 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003309{
Arend van Spriel1332e262012-11-05 16:22:18 -08003310 struct brcmf_if *ifp;
3311 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003312 s32 err = 0;
3313 u8 *iovar_ie_buf;
3314 u8 *curr_ie_buf;
3315 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003316 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003317 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003318 u32 del_add_ie_buf_len = 0;
3319 u32 total_ie_buf_len = 0;
3320 u32 parsed_ie_buf_len = 0;
3321 struct parsed_vndr_ies old_vndr_ies;
3322 struct parsed_vndr_ies new_vndr_ies;
3323 struct parsed_vndr_ie_info *vndrie_info;
3324 s32 i;
3325 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003326 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003327
Arend van Spriel1332e262012-11-05 16:22:18 -08003328 if (!vif)
3329 return -ENODEV;
3330 ifp = vif->ifp;
3331 saved_ie = &vif->saved_ie;
3332
Arend van Sprield96b8012012-12-05 15:26:02 +01003333 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003334 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3335 if (!iovar_ie_buf)
3336 return -ENOMEM;
3337 curr_ie_buf = iovar_ie_buf;
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003338 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003339 switch (pktflag) {
Arend van Spriel9f440b72013-02-08 15:53:36 +01003340 case BRCMF_VNDR_IE_PRBRSP_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003341 mgmt_ie_buf = saved_ie->probe_res_ie;
3342 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3343 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003344 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +01003345 case BRCMF_VNDR_IE_BEACON_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003346 mgmt_ie_buf = saved_ie->beacon_ie;
3347 mgmt_ie_len = &saved_ie->beacon_ie_len;
3348 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003349 break;
3350 default:
3351 err = -EPERM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003352 brcmf_err("not suitable type\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003353 goto exit;
3354 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003355 } else {
Arend van Spriel9f440b72013-02-08 15:53:36 +01003356 switch (pktflag) {
3357 case BRCMF_VNDR_IE_PRBREQ_FLAG:
3358 mgmt_ie_buf = saved_ie->probe_req_ie;
3359 mgmt_ie_len = &saved_ie->probe_req_ie_len;
3360 mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
3361 break;
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003362 case BRCMF_VNDR_IE_PRBRSP_FLAG:
3363 mgmt_ie_buf = saved_ie->probe_res_ie;
3364 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3365 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
3366 break;
Arend van Spriel9f440b72013-02-08 15:53:36 +01003367 default:
3368 err = -EPERM;
3369 brcmf_err("not suitable type\n");
3370 goto exit;
3371 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003372 }
3373
3374 if (vndr_ie_len > mgmt_ie_buf_len) {
3375 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003376 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003377 goto exit;
3378 }
3379
3380 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3381 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3382 ptr = curr_ie_buf;
3383 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3384 for (i = 0; i < new_vndr_ies.count; i++) {
3385 vndrie_info = &new_vndr_ies.ie_info[i];
3386 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3387 vndrie_info->ie_len);
3388 parsed_ie_buf_len += vndrie_info->ie_len;
3389 }
3390 }
3391
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003392 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003393 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3394 (memcmp(mgmt_ie_buf, curr_ie_buf,
3395 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003396 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003397 goto exit;
3398 }
3399
3400 /* parse old vndr_ie */
3401 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3402
3403 /* make a command to delete old ie */
3404 for (i = 0; i < old_vndr_ies.count; i++) {
3405 vndrie_info = &old_vndr_ies.ie_info[i];
3406
Arend van Sprield96b8012012-12-05 15:26:02 +01003407 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3408 vndrie_info->vndrie.id,
3409 vndrie_info->vndrie.len,
3410 vndrie_info->vndrie.oui[0],
3411 vndrie_info->vndrie.oui[1],
3412 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003413
3414 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3415 vndrie_info->ie_ptr,
3416 vndrie_info->ie_len,
3417 "del");
3418 curr_ie_buf += del_add_ie_buf_len;
3419 total_ie_buf_len += del_add_ie_buf_len;
3420 }
3421 }
3422
3423 *mgmt_ie_len = 0;
3424 /* Add if there is any extra IE */
3425 if (mgmt_ie_buf && parsed_ie_buf_len) {
3426 ptr = mgmt_ie_buf;
3427
3428 remained_buf_len = mgmt_ie_buf_len;
3429
3430 /* make a command to add new ie */
3431 for (i = 0; i < new_vndr_ies.count; i++) {
3432 vndrie_info = &new_vndr_ies.ie_info[i];
3433
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003434 /* verify remained buf size before copy data */
3435 if (remained_buf_len < (vndrie_info->vndrie.len +
3436 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003437 brcmf_err("no space in mgmt_ie_buf: len left %d",
3438 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003439 break;
3440 }
3441 remained_buf_len -= (vndrie_info->ie_len +
3442 VNDR_IE_VSIE_OFFSET);
3443
Arend van Sprield96b8012012-12-05 15:26:02 +01003444 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3445 vndrie_info->vndrie.id,
3446 vndrie_info->vndrie.len,
3447 vndrie_info->vndrie.oui[0],
3448 vndrie_info->vndrie.oui[1],
3449 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003450
3451 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3452 vndrie_info->ie_ptr,
3453 vndrie_info->ie_len,
3454 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003455
3456 /* save the parsed IE in wl struct */
3457 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3458 vndrie_info->ie_len);
3459 *mgmt_ie_len += vndrie_info->ie_len;
3460
3461 curr_ie_buf += del_add_ie_buf_len;
3462 total_ie_buf_len += del_add_ie_buf_len;
3463 }
3464 }
3465 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003466 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003467 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003468 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003469 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003470 }
3471
3472exit:
3473 kfree(iovar_ie_buf);
3474 return err;
3475}
3476
3477static s32
3478brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3479 struct cfg80211_ap_settings *settings)
3480{
3481 s32 ie_offset;
Arend van Sprielac24be62012-10-22 10:36:23 -07003482 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003483 struct brcmf_tlv *ssid_ie;
3484 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003485 s32 err = -EPERM;
3486 struct brcmf_tlv *rsn_ie;
3487 struct brcmf_vs_tlv *wpa_ie;
3488 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003489
Arend van Sprield96b8012012-12-05 15:26:02 +01003490 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3491 cfg80211_get_chandef_type(&settings->chandef),
3492 settings->beacon_interval,
3493 settings->dtim_period);
3494 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3495 settings->ssid, settings->ssid_len, settings->auth_type,
3496 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003497
Arend van Sprielc1179032012-10-22 13:55:33 -07003498 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003499 brcmf_err("Not in AP creation mode\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003500 return -EPERM;
3501 }
3502
3503 memset(&ssid_le, 0, sizeof(ssid_le));
3504 if (settings->ssid == NULL || settings->ssid_len == 0) {
3505 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3506 ssid_ie = brcmf_parse_tlvs(
3507 (u8 *)&settings->beacon.head[ie_offset],
3508 settings->beacon.head_len - ie_offset,
3509 WLAN_EID_SSID);
3510 if (!ssid_ie)
3511 return -EINVAL;
3512
3513 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3514 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003515 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003516 } else {
3517 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3518 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3519 }
3520
3521 brcmf_set_mpc(ndev, 0);
Arend van Sprielac24be62012-10-22 10:36:23 -07003522 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003523 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003524 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003525 goto exit;
3526 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003527 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003528 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003529 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003530 goto exit;
3531 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003532 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003533 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003534 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003535 goto exit;
3536 }
3537
3538 /* find the RSN_IE */
3539 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3540 settings->beacon.tail_len, WLAN_EID_RSN);
3541
3542 /* find the WPA_IE */
3543 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3544 settings->beacon.tail_len);
3545
Hante Meuleman1a873342012-09-27 14:17:54 +02003546 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003547 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003548 if (wpa_ie != NULL) {
3549 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003550 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003551 if (err < 0)
3552 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003553 } else {
3554 /* RSN IE */
3555 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003556 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003557 if (err < 0)
3558 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003559 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003560 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003561 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003562 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003563 }
3564 /* Set Beacon IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003565 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
Arend van Spriel9f440b72013-02-08 15:53:36 +01003566 BRCMF_VNDR_IE_BEACON_FLAG,
Arend van Spriel1332e262012-11-05 16:22:18 -08003567 settings->beacon.tail,
3568 settings->beacon.tail_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003569 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003570 brcmf_err("Set Beacon IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003571 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003572 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003573
3574 /* Set Probe Response IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003575 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
Arend van Spriel9f440b72013-02-08 15:53:36 +01003576 BRCMF_VNDR_IE_PRBRSP_FLAG,
Arend van Spriel1332e262012-11-05 16:22:18 -08003577 settings->beacon.proberesp_ies,
3578 settings->beacon.proberesp_ies_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003579 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003580 brcmf_err("Set Probe Resp IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003581 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003582 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003583
3584 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003585 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003586 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003587 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003588 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003589 goto exit;
3590 }
3591 }
3592 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003593 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003594 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003595 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003596 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003597 goto exit;
3598 }
3599 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003600 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003601 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003602 brcmf_err("BRCMF_C_UP error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003603 goto exit;
Hante Meuleman2880b862013-02-08 12:06:31 +01003604 brcmf_fil_iovar_int_set(ifp, "apsta", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003605 }
3606
3607 memset(&join_params, 0, sizeof(join_params));
3608 /* join parameters starts with ssid */
3609 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3610 /* create softap */
Arend van Sprielac24be62012-10-22 10:36:23 -07003611 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3612 &join_params, sizeof(join_params));
Hante Meuleman1a873342012-09-27 14:17:54 +02003613 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003614 brcmf_err("SET SSID error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003615 goto exit;
3616 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003617 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3618 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003619
3620exit:
3621 if (err)
3622 brcmf_set_mpc(ndev, 1);
3623 return err;
3624}
3625
3626static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3627{
Arend van Sprielc1179032012-10-22 13:55:33 -07003628 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003629 s32 err = -EPERM;
3630
Arend van Sprield96b8012012-12-05 15:26:02 +01003631 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003632
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003633 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003634 /* Due to most likely deauths outstanding we sleep */
3635 /* first to make sure they get processed by fw. */
3636 msleep(400);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003637 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003638 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003639 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003640 goto exit;
3641 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003642 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003643 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003644 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003645 goto exit;
3646 }
3647 brcmf_set_mpc(ndev, 1);
Arend van Sprielc1179032012-10-22 13:55:33 -07003648 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3649 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003650 }
3651exit:
3652 return err;
3653}
3654
3655static int
3656brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3657 u8 *mac)
3658{
3659 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003660 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003661 s32 err;
3662
3663 if (!mac)
3664 return -EFAULT;
3665
Arend van Sprield96b8012012-12-05 15:26:02 +01003666 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003667
Arend van Sprielce81e312012-10-22 13:55:37 -07003668 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003669 return -EIO;
3670
3671 memcpy(&scbval.ea, mac, ETH_ALEN);
3672 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003673 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003674 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003675 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003676 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003677
Arend van Sprield96b8012012-12-05 15:26:02 +01003678 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003679 return err;
3680}
3681
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003682
3683static void
3684brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
3685 struct wireless_dev *wdev,
3686 u16 frame_type, bool reg)
3687{
3688 struct brcmf_if *ifp = netdev_priv(wdev->netdev);
3689 struct brcmf_cfg80211_vif *vif = ifp->vif;
3690 u16 mgmt_type;
3691
3692 brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
3693
3694 mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
3695 if (reg)
3696 vif->mgmt_rx_reg |= BIT(mgmt_type);
3697 else
3698 vif->mgmt_rx_reg |= ~BIT(mgmt_type);
3699}
3700
3701
3702static int
3703brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3704 struct ieee80211_channel *chan, bool offchan,
3705 unsigned int wait, const u8 *buf, size_t len,
3706 bool no_cck, bool dont_wait_for_ack, u64 *cookie)
3707{
3708 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3709 const struct ieee80211_mgmt *mgmt;
3710 struct brcmf_cfg80211_vif *vif;
3711 s32 err = 0;
3712 s32 ie_offset;
3713 s32 ie_len;
3714
3715 brcmf_dbg(TRACE, "Enter\n");
3716
3717 *cookie = 0;
3718
3719 mgmt = (const struct ieee80211_mgmt *)buf;
3720
3721 if (ieee80211_is_mgmt(mgmt->frame_control)) {
3722 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
3723 /* Right now the only reason to get a probe response */
3724 /* is for p2p listen response from wpa_supplicant. */
3725 /* Unfortunately the wpa_supplicant sends it on the */
3726 /* primary ndev, while dongle wants it on the p2p */
3727 /* vif. Since this is only reason for a probe */
3728 /* response to be sent, the vif is taken from cfg. */
3729 /* If ever desired to send proberesp for non p2p */
3730 /* response then data should be checked for */
3731 /* "DIRECT-". Note in future supplicant will take */
3732 /* dedicated p2p wdev to do this and then this 'hack'*/
3733 /* is not needed anymore. */
3734 ie_offset = DOT11_MGMT_HDR_LEN +
3735 DOT11_BCN_PRB_FIXED_LEN;
3736 ie_len = len - ie_offset;
3737
3738 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
3739 if (vif == NULL) {
3740 brcmf_err("No p2p device available for probe response\n");
3741 err = -ENODEV;
3742 goto exit;
3743 }
3744 err = brcmf_vif_set_mgmt_ie(vif,
3745 BRCMF_VNDR_IE_PRBRSP_FLAG,
3746 &buf[ie_offset],
3747 ie_len);
3748 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
3749 GFP_KERNEL);
3750 goto exit;
3751 }
3752 }
3753 brcmf_dbg(TRACE, "Unhandled, is_mgmt %d, fc=%04x!!!!!\n",
3754 ieee80211_is_mgmt(mgmt->frame_control), mgmt->frame_control);
3755exit:
3756 return err;
3757}
3758
3759
3760static int
3761brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
3762 struct wireless_dev *wdev,
3763 u64 cookie)
3764{
3765 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3766 struct brcmf_cfg80211_vif *vif;
3767 int err = 0;
3768
3769 brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
3770
3771 vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
3772 if (vif == NULL) {
3773 brcmf_err("No p2p device available for probe response\n");
3774 err = -ENODEV;
3775 goto exit;
3776 }
3777 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
3778exit:
3779 return err;
3780}
3781
3782static s32 brcmf_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
3783 const struct brcmf_event_msg *e,
3784 void *data)
3785{
3786 struct wireless_dev *wdev;
3787 struct brcmf_cfg80211_vif *vif = ifp->vif;
3788 struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
3789 u16 chanspec = be16_to_cpu(rxframe->chanspec);
3790 u8 *mgmt_frame;
3791 u32 mgmt_frame_len;
3792 s32 freq;
3793 u16 mgmt_type;
3794
3795 brcmf_dbg(INFO,
3796 "Enter: event %d reason %d\n", e->event_code, e->reason);
3797
3798 /* Firmware sends us two proberesponses for each idx one. At the */
3799 /* moment only bsscfgidx 0 is passed up to supplicant */
3800 if (e->bsscfgidx)
3801 return 0;
3802
3803 /* Check if wpa_supplicant has registered for this frame */
3804 brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
3805 mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
3806 if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
3807 return 0;
3808
3809 mgmt_frame = (u8 *)(rxframe + 1);
3810 mgmt_frame_len = e->datalen - sizeof(*rxframe);
3811 freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
3812 CHSPEC_IS2G(chanspec) ?
3813 IEEE80211_BAND_2GHZ :
3814 IEEE80211_BAND_5GHZ);
3815 wdev = ifp->ndev->ieee80211_ptr;
3816 cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
3817
3818 brcmf_dbg(INFO,
3819 "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
3820 mgmt_frame_len, e->datalen, chanspec, freq);
3821
3822 return 0;
3823}
3824
3825
Arend van Spriel5b435de2011-10-05 13:19:03 +02003826static struct cfg80211_ops wl_cfg80211_ops = {
Arend van Spriel9f440b72013-02-08 15:53:36 +01003827 .add_virtual_intf = brcmf_cfg80211_add_iface,
3828 .del_virtual_intf = brcmf_cfg80211_del_iface,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003829 .change_virtual_intf = brcmf_cfg80211_change_iface,
3830 .scan = brcmf_cfg80211_scan,
3831 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
3832 .join_ibss = brcmf_cfg80211_join_ibss,
3833 .leave_ibss = brcmf_cfg80211_leave_ibss,
3834 .get_station = brcmf_cfg80211_get_station,
3835 .set_tx_power = brcmf_cfg80211_set_tx_power,
3836 .get_tx_power = brcmf_cfg80211_get_tx_power,
3837 .add_key = brcmf_cfg80211_add_key,
3838 .del_key = brcmf_cfg80211_del_key,
3839 .get_key = brcmf_cfg80211_get_key,
3840 .set_default_key = brcmf_cfg80211_config_default_key,
3841 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
3842 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003843 .connect = brcmf_cfg80211_connect,
3844 .disconnect = brcmf_cfg80211_disconnect,
3845 .suspend = brcmf_cfg80211_suspend,
3846 .resume = brcmf_cfg80211_resume,
3847 .set_pmksa = brcmf_cfg80211_set_pmksa,
3848 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003849 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02003850 .start_ap = brcmf_cfg80211_start_ap,
3851 .stop_ap = brcmf_cfg80211_stop_ap,
3852 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02003853 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
3854 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003855 .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
3856 .mgmt_tx = brcmf_cfg80211_mgmt_tx,
3857 .remain_on_channel = brcmf_p2p_remain_on_channel,
3858 .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003859#ifdef CONFIG_NL80211_TESTMODE
3860 .testmode_cmd = brcmf_cfg80211_testmode
3861#endif
Arend van Spriel5b435de2011-10-05 13:19:03 +02003862};
3863
Arend van Spriel9f440b72013-02-08 15:53:36 +01003864static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003865{
Arend van Spriel9f440b72013-02-08 15:53:36 +01003866 switch (type) {
3867 case NL80211_IFTYPE_AP_VLAN:
3868 case NL80211_IFTYPE_WDS:
3869 case NL80211_IFTYPE_MONITOR:
3870 case NL80211_IFTYPE_MESH_POINT:
3871 return -ENOTSUPP;
3872 case NL80211_IFTYPE_ADHOC:
3873 return WL_MODE_IBSS;
3874 case NL80211_IFTYPE_STATION:
3875 case NL80211_IFTYPE_P2P_CLIENT:
3876 return WL_MODE_BSS;
3877 case NL80211_IFTYPE_AP:
3878 case NL80211_IFTYPE_P2P_GO:
3879 return WL_MODE_AP;
3880 case NL80211_IFTYPE_P2P_DEVICE:
3881 return WL_MODE_P2P;
3882 case NL80211_IFTYPE_UNSPECIFIED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02003883 default:
Arend van Spriel9f440b72013-02-08 15:53:36 +01003884 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003885 }
3886
Arend van Spriel9f440b72013-02-08 15:53:36 +01003887 return -EINVAL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003888}
3889
Arend van Spriele5806072012-09-19 22:21:08 +02003890static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
3891{
Arend van Spriele5806072012-09-19 22:21:08 +02003892 /* scheduled scan settings */
3893 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
3894 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
3895 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3896 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02003897}
3898
Arend van Spriel9f440b72013-02-08 15:53:36 +01003899static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
3900 {
3901 .max = 1,
3902 .types = BIT(NL80211_IFTYPE_STATION) |
3903 BIT(NL80211_IFTYPE_ADHOC) |
3904 BIT(NL80211_IFTYPE_AP)
3905 },
3906 {
3907 .max = 1,
3908 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
3909 BIT(NL80211_IFTYPE_P2P_GO)
3910 },
3911};
3912static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
3913 {
3914 .max_interfaces = BRCMF_IFACE_MAX_CNT - 1,
3915 .num_different_channels = 1, /* no multi-channel for now */
3916 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
3917 .limits = brcmf_iface_limits
3918 }
3919};
3920
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003921static const struct ieee80211_txrx_stypes
3922brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
3923 [NL80211_IFTYPE_STATION] = {
3924 .tx = 0xffff,
3925 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3926 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3927 },
3928 [NL80211_IFTYPE_P2P_CLIENT] = {
3929 .tx = 0xffff,
3930 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
3931 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
3932 },
3933 [NL80211_IFTYPE_P2P_GO] = {
3934 .tx = 0xffff,
3935 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
3936 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
3937 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
3938 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
3939 BIT(IEEE80211_STYPE_AUTH >> 4) |
3940 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
3941 BIT(IEEE80211_STYPE_ACTION >> 4)
3942 }
3943};
3944
Arend van Spriel3eacf862012-10-22 13:55:30 -07003945static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003946{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003947 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003948 s32 err = 0;
3949
Arend van Spriel3eacf862012-10-22 13:55:30 -07003950 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
3951 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003952 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07003953 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003954 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003955 set_wiphy_dev(wiphy, phydev);
3956 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
Arend van Spriel9f440b72013-02-08 15:53:36 +01003957 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
Arend van Spriel3eacf862012-10-22 13:55:30 -07003958 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
3959 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3960 BIT(NL80211_IFTYPE_ADHOC) |
Arend van Spriel9f440b72013-02-08 15:53:36 +01003961 BIT(NL80211_IFTYPE_AP) |
3962 BIT(NL80211_IFTYPE_P2P_CLIENT) |
3963 BIT(NL80211_IFTYPE_P2P_GO);
3964 wiphy->iface_combinations = brcmf_iface_combos;
3965 wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003966 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3967 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
Arend van Spriel5b435de2011-10-05 13:19:03 +02003968 * it as 11a by default.
3969 * This will be updated with
3970 * 11n phy tables in
3971 * "ifconfig up"
3972 * if phy has 11n capability
3973 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07003974 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3975 wiphy->cipher_suites = __wl_cipher_suites;
3976 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01003977 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
3978 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
3979 wiphy->mgmt_stypes = brcmf_txrx_stypes;
3980 wiphy->max_remain_on_channel_duration = 5000;
Arend van Spriel3eacf862012-10-22 13:55:30 -07003981 brcmf_wiphy_pno_params(wiphy);
3982 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003983 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003984 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003985 wiphy_free(wiphy);
3986 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003987 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003988 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003989}
3990
Arend van Spriel3eacf862012-10-22 13:55:30 -07003991struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
Arend van Spriel9f440b72013-02-08 15:53:36 +01003992 enum nl80211_iftype type,
3993 bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003994{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003995 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003996
Arend van Spriel3eacf862012-10-22 13:55:30 -07003997 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
3998 return ERR_PTR(-ENOSPC);
3999
Arend van Spriel9f440b72013-02-08 15:53:36 +01004000 brcmf_dbg(TRACE, "allocating virtual interface (size=%d)\n",
4001 sizeof(*vif));
Arend van Spriel3eacf862012-10-22 13:55:30 -07004002 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4003 if (!vif)
4004 return ERR_PTR(-ENOMEM);
4005
4006 vif->wdev.wiphy = cfg->wiphy;
Arend van Spriel9f440b72013-02-08 15:53:36 +01004007 vif->wdev.iftype = type;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004008
Arend van Spriel9f440b72013-02-08 15:53:36 +01004009 vif->mode = brcmf_nl80211_iftype_to_mode(type);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004010 vif->pm_block = pm_block;
4011 vif->roam_off = -1;
4012
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004013 brcmf_init_prof(&vif->profile);
4014
Arend van Spriel3eacf862012-10-22 13:55:30 -07004015 list_add_tail(&vif->list, &cfg->vif_list);
4016 cfg->vif_cnt++;
4017 return vif;
4018}
4019
Arend van Spriel9f440b72013-02-08 15:53:36 +01004020void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
Arend van Spriel3eacf862012-10-22 13:55:30 -07004021{
4022 struct brcmf_cfg80211_info *cfg;
4023 struct wiphy *wiphy;
4024
4025 wiphy = vif->wdev.wiphy;
4026 cfg = wiphy_priv(wiphy);
4027 list_del(&vif->list);
4028 cfg->vif_cnt--;
4029
4030 kfree(vif);
4031 if (!cfg->vif_cnt) {
4032 wiphy_unregister(wiphy);
4033 wiphy_free(wiphy);
4034 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004035}
4036
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004037static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004038{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004039 u32 event = e->event_code;
4040 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004041
4042 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004043 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004044 return true;
4045 }
4046
4047 return false;
4048}
4049
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004050static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004051{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004052 u32 event = e->event_code;
4053 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004054
4055 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01004056 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004057 return true;
4058 }
4059 return false;
4060}
4061
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004062static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004063 const struct brcmf_event_msg *e)
4064{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004065 u32 event = e->event_code;
4066 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004067
4068 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01004069 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
4070 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004071 return true;
4072 }
4073
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 connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004076 return true;
4077 }
4078
4079 return false;
4080}
4081
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004082static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004083{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004084 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004085
4086 kfree(conn_info->req_ie);
4087 conn_info->req_ie = NULL;
4088 conn_info->req_ie_len = 0;
4089 kfree(conn_info->resp_ie);
4090 conn_info->resp_ie = NULL;
4091 conn_info->resp_ie_len = 0;
4092}
4093
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004094static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004095{
Arend van Sprielac24be62012-10-22 10:36:23 -07004096 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004097 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004098 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004099 u32 req_len;
4100 u32 resp_len;
4101 s32 err = 0;
4102
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004103 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004104
Arend van Sprielac24be62012-10-22 10:36:23 -07004105 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4106 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004107 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004108 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004109 return err;
4110 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004111 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004112 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004113 req_len = le32_to_cpu(assoc_info->req_len);
4114 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004115 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004116 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004117 cfg->extra_buf,
4118 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004119 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004120 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004121 return err;
4122 }
4123 conn_info->req_ie_len = req_len;
4124 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004125 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004126 GFP_KERNEL);
4127 } else {
4128 conn_info->req_ie_len = 0;
4129 conn_info->req_ie = NULL;
4130 }
4131 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004132 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004133 cfg->extra_buf,
4134 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004135 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004136 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004137 return err;
4138 }
4139 conn_info->resp_ie_len = resp_len;
4140 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004141 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004142 GFP_KERNEL);
4143 } else {
4144 conn_info->resp_ie_len = 0;
4145 conn_info->resp_ie = NULL;
4146 }
Arend van Spriel16886732012-12-05 15:26:04 +01004147 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
4148 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004149
4150 return err;
4151}
4152
4153static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004154brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004155 struct net_device *ndev,
4156 const struct brcmf_event_msg *e)
4157{
Arend van Sprielc1179032012-10-22 13:55:33 -07004158 struct brcmf_if *ifp = netdev_priv(ndev);
4159 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004160 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4161 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004162 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004163 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004164 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004165 u32 freq;
4166 s32 err = 0;
4167 u32 target_channel;
Franky Lina180b832012-10-10 11:13:09 -07004168 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004169
Arend van Sprield96b8012012-12-05 15:26:02 +01004170 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004171
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004172 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004173 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004174 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004175
Franky Lina180b832012-10-10 11:13:09 -07004176 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4177 if (buf == NULL) {
4178 err = -ENOMEM;
4179 goto done;
4180 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004181
Franky Lina180b832012-10-10 11:13:09 -07004182 /* data sent to dongle has to be little endian */
4183 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004184 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004185 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004186
4187 if (err)
4188 goto done;
4189
4190 bi = (struct brcmf_bss_info_le *)(buf + 4);
4191 target_channel = bi->ctl_ch ? bi->ctl_ch :
4192 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004193
4194 if (target_channel <= CH_MAX_2G_CHANNEL)
4195 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4196 else
4197 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4198
4199 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4200 notify_channel = ieee80211_get_channel(wiphy, freq);
4201
Franky Lina180b832012-10-10 11:13:09 -07004202done:
4203 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004204 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004205 conn_info->req_ie, conn_info->req_ie_len,
4206 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01004207 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004208
Arend van Sprielc1179032012-10-22 13:55:33 -07004209 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01004210 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004211 return err;
4212}
4213
4214static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004215brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004216 struct net_device *ndev, const struct brcmf_event_msg *e,
4217 bool completed)
4218{
Arend van Sprielc1179032012-10-22 13:55:33 -07004219 struct brcmf_if *ifp = netdev_priv(ndev);
4220 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004221 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004222 s32 err = 0;
4223
Arend van Sprield96b8012012-12-05 15:26:02 +01004224 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004225
Arend van Sprielc1179032012-10-22 13:55:33 -07004226 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4227 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004228 if (completed) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004229 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004230 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004231 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004232 }
4233 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004234 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004235 conn_info->req_ie,
4236 conn_info->req_ie_len,
4237 conn_info->resp_ie,
4238 conn_info->resp_ie_len,
4239 completed ? WLAN_STATUS_SUCCESS :
4240 WLAN_STATUS_AUTH_TIMEOUT,
4241 GFP_KERNEL);
4242 if (completed)
Arend van Sprielc1179032012-10-22 13:55:33 -07004243 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4244 &ifp->vif->sme_state);
Arend van Spriel16886732012-12-05 15:26:04 +01004245 brcmf_dbg(CONN, "Report connect result - connection %s\n",
4246 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004247 }
Arend van Sprield96b8012012-12-05 15:26:02 +01004248 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004249 return err;
4250}
4251
4252static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004253brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004254 struct net_device *ndev,
4255 const struct brcmf_event_msg *e, void *data)
4256{
Hante Meuleman7ee29602013-02-06 18:40:43 +01004257 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004258 u32 event = e->event_code;
4259 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02004260 struct station_info sinfo;
4261
Arend van Spriel16886732012-12-05 15:26:04 +01004262 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Hante Meuleman1a873342012-09-27 14:17:54 +02004263
Hante Meuleman1a873342012-09-27 14:17:54 +02004264 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004265 (reason == BRCMF_E_STATUS_SUCCESS)) {
4266 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004267 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4268 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004269 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004270 return -EINVAL;
4271 }
4272 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004273 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004274 generation++;
4275 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004276 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004277 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4278 (event == BRCMF_E_DEAUTH_IND) ||
4279 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004280 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004281 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004282 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004283}
4284
4285static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004286brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004287 const struct brcmf_event_msg *e, void *data)
4288{
Arend van Spriel19937322012-11-05 16:22:32 -08004289 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4290 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004291 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004292 s32 err = 0;
4293
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004294 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004295 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004296 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004297 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004298 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004299 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004300 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004301 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004302 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4303 &ifp->vif->sme_state);
4304 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4305 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004306 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004307 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004308 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004309 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004310 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004311 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004312 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004313 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004314 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004315 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004316 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004317 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004318 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004319 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004320 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004321 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4322 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004323 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004324 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004325 }
4326
4327 return err;
4328}
4329
4330static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004331brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004332 const struct brcmf_event_msg *e, void *data)
4333{
Arend van Spriel19937322012-11-05 16:22:32 -08004334 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004335 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004336 u32 event = e->event_code;
4337 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004338
4339 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004340 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004341 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004342 else
Arend van Spriel19937322012-11-05 16:22:32 -08004343 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004344 }
4345
4346 return err;
4347}
4348
4349static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004350brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004351 const struct brcmf_event_msg *e, void *data)
4352{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004353 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004354 enum nl80211_key_type key_type;
4355
4356 if (flags & BRCMF_EVENT_MSG_GROUP)
4357 key_type = NL80211_KEYTYPE_GROUP;
4358 else
4359 key_type = NL80211_KEYTYPE_PAIRWISE;
4360
Arend van Spriel19937322012-11-05 16:22:32 -08004361 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004362 NULL, GFP_KERNEL);
4363
4364 return 0;
4365}
4366
Arend van Sprield3c0b632013-02-08 15:53:37 +01004367static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4368 const struct brcmf_event_msg *e, void *data)
4369{
4370 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4371 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
4372 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4373 struct brcmf_cfg80211_vif *vif;
4374
4375 brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
4376 ifevent->action, ifevent->flags, ifevent->ifidx,
4377 ifevent->bssidx);
4378
4379
4380 mutex_lock(&event->vif_event_lock);
4381 event->action = ifevent->action;
4382 vif = event->vif;
4383
4384 switch (ifevent->action) {
4385 case BRCMF_E_IF_ADD:
4386 /* waiting process may have timed out */
4387 if (!cfg->vif_event.vif)
4388 return -EBADF;
4389
4390 ifp->vif = vif;
4391 vif->ifp = ifp;
4392 vif->wdev.netdev = ifp->ndev;
4393 ifp->ndev->ieee80211_ptr = &vif->wdev;
4394 SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
4395 mutex_unlock(&event->vif_event_lock);
4396 wake_up(&event->vif_wq);
4397
4398 /* waiting process need to set the netdev name */
4399 wait_for_completion(&event->vif_complete);
4400 return brcmf_net_attach(ifp);
4401
4402 case BRCMF_E_IF_DEL:
4403 ifp->vif = NULL;
4404 brcmf_free_vif(vif);
4405 mutex_unlock(&event->vif_event_lock);
4406 /* event may not be upon user request */
4407 if (brcmf_cfg80211_vif_event_armed(cfg))
4408 wake_up(&event->vif_wq);
4409 return 0;
4410
4411 default:
4412 mutex_unlock(&event->vif_event_lock);
4413 break;
4414 }
4415 return -EINVAL;
4416}
4417
Arend van Spriel5b435de2011-10-05 13:19:03 +02004418static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4419{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004420 conf->frag_threshold = (u32)-1;
4421 conf->rts_threshold = (u32)-1;
4422 conf->retry_short = (u32)-1;
4423 conf->retry_long = (u32)-1;
4424 conf->tx_power = -1;
4425}
4426
Arend van Spriel5c36b992012-11-14 18:46:05 -08004427static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004428{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004429 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4430 brcmf_notify_connect_status);
4431 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4432 brcmf_notify_connect_status);
4433 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4434 brcmf_notify_connect_status);
4435 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4436 brcmf_notify_connect_status);
4437 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4438 brcmf_notify_connect_status);
4439 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4440 brcmf_notify_connect_status);
4441 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4442 brcmf_notify_roaming_status);
4443 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4444 brcmf_notify_mic_status);
4445 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4446 brcmf_notify_connect_status);
4447 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4448 brcmf_notify_sched_scan_results);
Arend van Sprield3c0b632013-02-08 15:53:37 +01004449 brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
4450 brcmf_notify_vif_event);
Hante Meuleman0de8aac2013-02-08 15:53:38 +01004451 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
4452 brcmf_notify_rx_mgmt_p2p_probereq);
4453 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4454 brcmf_p2p_notify_listen_complete);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004455}
4456
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004457static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004458{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004459 kfree(cfg->conf);
4460 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004461 kfree(cfg->escan_ioctl_buf);
4462 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004463 kfree(cfg->extra_buf);
4464 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004465 kfree(cfg->pmk_list);
4466 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004467}
4468
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004469static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004470{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004471 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4472 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004473 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004474 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4475 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004476 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004477 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4478 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004479 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004480 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4481 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004482 goto init_priv_mem_out;
4483
4484 return 0;
4485
4486init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004487 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004488
4489 return -ENOMEM;
4490}
4491
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004492static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004493{
4494 s32 err = 0;
4495
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004496 cfg->scan_request = NULL;
4497 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004498 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004499 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004500 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004501 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004502 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004503 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004504 if (err)
4505 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004506 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004507 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004508 brcmf_init_escan(cfg);
4509 brcmf_init_conf(cfg->conf);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004510
4511 return err;
4512}
4513
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004514static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004515{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004516 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004517 brcmf_abort_scanning(cfg);
4518 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004519}
4520
Arend van Sprield3c0b632013-02-08 15:53:37 +01004521static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
4522{
4523 init_waitqueue_head(&event->vif_wq);
4524 init_completion(&event->vif_complete);
4525 mutex_init(&event->vif_event_lock);
4526}
4527
Arend van Sprield9cb2592012-12-05 15:25:54 +01004528struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4529 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004530{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004531 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004532 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004533 struct wiphy *wiphy;
4534 struct brcmf_cfg80211_vif *vif;
4535 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004536 s32 err = 0;
4537
4538 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004539 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004540 return NULL;
4541 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004542
Arend van Spriel3eacf862012-10-22 13:55:30 -07004543 ifp = netdev_priv(ndev);
4544 wiphy = brcmf_setup_wiphy(busdev);
4545 if (IS_ERR(wiphy))
4546 return NULL;
4547
4548 cfg = wiphy_priv(wiphy);
4549 cfg->wiphy = wiphy;
4550 cfg->pub = drvr;
Arend van Sprield3c0b632013-02-08 15:53:37 +01004551 init_vif_event(&cfg->vif_event);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004552 INIT_LIST_HEAD(&cfg->vif_list);
4553
Arend van Sprield3c0b632013-02-08 15:53:37 +01004554 vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004555 if (IS_ERR(vif)) {
4556 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004557 return NULL;
4558 }
4559
Arend van Sprield3c0b632013-02-08 15:53:37 +01004560 vif->ifp = ifp;
4561 vif->wdev.netdev = ndev;
4562 ndev->ieee80211_ptr = &vif->wdev;
4563 SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
4564
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004565 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004566 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004567 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004568 goto cfg80211_attach_out;
4569 }
Arend van Spriel9f440b72013-02-08 15:53:36 +01004570 brcmf_p2p_attach(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004571
Arend van Spriel3eacf862012-10-22 13:55:30 -07004572 ifp->vif = vif;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004573 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004574
4575cfg80211_attach_out:
Arend van Spriel3eacf862012-10-22 13:55:30 -07004576 brcmf_free_vif(vif);
Hante Meuleman2880b862013-02-08 12:06:31 +01004577 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004578 return NULL;
4579}
4580
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004581void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004582{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004583 struct brcmf_cfg80211_vif *vif;
4584 struct brcmf_cfg80211_vif *tmp;
4585
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004586 wl_deinit_priv(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004587 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4588 brcmf_free_vif(vif);
4589 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004590}
4591
Arend van Spriel5b435de2011-10-05 13:19:03 +02004592static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004593brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004594{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004595 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02004596 __le32 roamtrigger[2];
4597 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02004598
4599 /*
4600 * Setup timeout if Beacons are lost and roam is
4601 * off to report link down
4602 */
4603 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004604 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004605 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004606 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004607 goto dongle_rom_out;
4608 }
4609 }
4610
4611 /*
4612 * Enable/Disable built-in roaming to allow supplicant
4613 * to take care of roaming
4614 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004615 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07004616 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004617 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004618 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004619 goto dongle_rom_out;
4620 }
4621
Arend van Sprielf588bc02011-10-12 20:51:22 +02004622 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4623 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004624 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004625 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004626 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004627 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004628 goto dongle_rom_out;
4629 }
4630
Arend van Sprielf588bc02011-10-12 20:51:22 +02004631 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4632 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004633 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004634 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004635 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004636 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004637 goto dongle_rom_out;
4638 }
4639
4640dongle_rom_out:
4641 return err;
4642}
4643
4644static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004645brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02004646 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004647{
4648 s32 err = 0;
4649
Arend van Sprielac24be62012-10-22 10:36:23 -07004650 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004651 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004652 if (err) {
4653 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004654 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004655 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004656 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004657 goto dongle_scantime_out;
4658 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004659 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004660 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004661 if (err) {
4662 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004663 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004664 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004665 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004666 goto dongle_scantime_out;
4667 }
4668
Arend van Sprielac24be62012-10-22 10:36:23 -07004669 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004670 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004671 if (err) {
4672 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004673 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004674 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004675 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004676 goto dongle_scantime_out;
4677 }
4678
4679dongle_scantime_out:
4680 return err;
4681}
4682
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004683static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004684{
Arend van Sprielac24be62012-10-22 10:36:23 -07004685 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004686 struct wiphy *wiphy;
4687 s32 phy_list;
4688 s8 phy;
4689 s32 err = 0;
4690
Hante Meulemanb87e2c42012-11-14 18:46:23 -08004691 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004692 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004693 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004694 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004695 return err;
4696 }
4697
Hante Meuleman3ba81372012-09-19 22:21:13 +02004698 phy = ((char *)&phy_list)[0];
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004699 brcmf_dbg(INFO, "%c phy\n", phy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004700 if (phy == 'n' || phy == 'a') {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004701 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004702 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4703 }
4704
4705 return err;
4706}
4707
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004708static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004709{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004710 return wl_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004711}
4712
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004713static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004714{
4715 struct net_device *ndev;
4716 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01004717 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004718 s32 power_mode;
4719 s32 err = 0;
4720
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004721 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004722 return err;
4723
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004724 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004725 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01004726 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004727
Hante Meuleman40a23292013-01-02 15:22:51 +01004728 /* make sure RF is ready for work */
4729 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
4730
4731 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
4732 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004733
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004734 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01004735 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004736 if (err)
4737 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004738 brcmf_dbg(INFO, "power save set to %s\n",
4739 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004740
Hante Meuleman40a23292013-01-02 15:22:51 +01004741 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004742 if (err)
4743 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07004744 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
4745 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01004746 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004747 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004748 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004749 if (err)
4750 goto default_conf_out;
4751
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004752 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01004753default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004754
4755 return err;
4756
4757}
4758
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004759static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004760{
Arend van Sprielc1179032012-10-22 13:55:33 -07004761 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004762
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004763 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004764}
4765
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004766static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004767{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004768 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07004769
Arend van Spriel5b435de2011-10-05 13:19:03 +02004770 /*
4771 * While going down, if associated with AP disassociate
4772 * from AP to save power
4773 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004774 if (check_vif_up(ifp->vif)) {
4775 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004776
4777 /* Make sure WPA_Supplicant receives all the event
4778 generated due to DISASSOC call to the fw to keep
4779 the state fw and WPA_Supplicant state consistent
4780 */
4781 brcmf_delay(500);
4782 }
4783
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004784 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07004785 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004786
Arend van Spriel5b435de2011-10-05 13:19:03 +02004787 return 0;
4788}
4789
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004790s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004791{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004792 struct brcmf_if *ifp = netdev_priv(ndev);
4793 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004794 s32 err = 0;
4795
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004796 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004797 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004798 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004799
4800 return err;
4801}
4802
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004803s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004804{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004805 struct brcmf_if *ifp = netdev_priv(ndev);
4806 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004807 s32 err = 0;
4808
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004809 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004810 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004811 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004812
4813 return err;
4814}
4815
Arend van Spriel9f440b72013-02-08 15:53:36 +01004816u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
4817{
4818 struct brcmf_cfg80211_vif *vif;
4819 bool result = 0;
4820
4821 list_for_each_entry(vif, &cfg->vif_list, list) {
4822 if (test_bit(state, &vif->sme_state))
4823 result++;
4824 }
4825 return result;
4826}
Arend van Sprield3c0b632013-02-08 15:53:37 +01004827
4828static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
4829 u8 action)
4830{
4831 u8 evt_action;
4832
4833 mutex_lock(&event->vif_event_lock);
4834 evt_action = event->action;
4835 mutex_unlock(&event->vif_event_lock);
4836 return evt_action == action;
4837}
4838
4839void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
4840 struct brcmf_cfg80211_vif *vif)
4841{
4842 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4843
4844 mutex_lock(&event->vif_event_lock);
4845 event->vif = vif;
4846 event->action = 0;
4847 mutex_unlock(&event->vif_event_lock);
4848}
4849
4850bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
4851{
4852 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4853 bool armed;
4854
4855 mutex_lock(&event->vif_event_lock);
4856 armed = event->vif != NULL;
4857 mutex_unlock(&event->vif_event_lock);
4858
4859 return armed;
4860}
4861int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
4862 u8 action, ulong timeout)
4863{
4864 struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
4865
4866 return wait_event_timeout(event->vif_wq,
4867 vif_event_equals(event, action), timeout);
4868}
4869
4870void brcmf_cfg80211_vif_complete(struct brcmf_cfg80211_info *cfg)
4871{
4872 complete(&cfg->vif_event.vif_complete);
4873}