blob: cbad77261ee4d207eacaf02bdc2983e1b9cfc40c [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
Joe Perches02f77192012-01-15 00:38:44 -080019#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
Arend van Spriel5b435de2011-10-05 13:19:03 +020021#include <linux/kernel.h>
22#include <linux/if_arp.h>
23#include <linux/sched.h>
24#include <linux/kthread.h>
25#include <linux/netdevice.h>
26#include <linux/bitops.h>
27#include <linux/etherdevice.h>
28#include <linux/ieee80211.h>
29#include <linux/uaccess.h>
30#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020031#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020032
33#include <brcmu_utils.h>
34#include <defs.h>
35#include <brcmu_wifi.h>
36#include "dhd.h"
37#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070038#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020039
Arend van Spriele5806072012-09-19 22:21:08 +020040#define BRCMF_SCAN_IE_LEN_MAX 2048
41#define BRCMF_PNO_VERSION 2
42#define BRCMF_PNO_TIME 30
43#define BRCMF_PNO_REPEAT 4
44#define BRCMF_PNO_FREQ_EXPO_MAX 3
45#define BRCMF_PNO_MAX_PFN_COUNT 16
46#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
47#define BRCMF_PNO_HIDDEN_BIT 2
48#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
49#define BRCMF_PNO_SCAN_COMPLETE 1
50#define BRCMF_PNO_SCAN_INCOMPLETE 0
51
Arend van Spriel3eacf862012-10-22 13:55:30 -070052#define BRCMF_IFACE_MAX_CNT 2
53
Hante Meuleman1a873342012-09-27 14:17:54 +020054#define TLV_LEN_OFF 1 /* length offset */
Hante Meuleman04012892012-09-27 14:17:49 +020055#define TLV_HDR_LEN 2 /* header length */
Hante Meuleman1a873342012-09-27 14:17:54 +020056#define TLV_BODY_OFF 2 /* body offset */
57#define TLV_OUI_LEN 3 /* oui id length */
58#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
59#define WPA_OUI_TYPE 1
60#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
61#define WME_OUI_TYPE 2
62
63#define VS_IE_FIXED_HDR_LEN 6
64#define WPA_IE_VERSION_LEN 2
65#define WPA_IE_MIN_OUI_LEN 4
66#define WPA_IE_SUITE_COUNT_LEN 2
67
68#define WPA_CIPHER_NONE 0 /* None */
69#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
70#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
71#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
72#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
73
74#define RSN_AKM_NONE 0 /* None (IBSS) */
75#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
76#define RSN_AKM_PSK 2 /* Pre-shared Key */
77#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
78#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
79
80#define VNDR_IE_CMD_LEN 4 /* length of the set command
81 * string :"add", "del" (+ NUL)
82 */
83#define VNDR_IE_COUNT_OFFSET 4
84#define VNDR_IE_PKTFLAG_OFFSET 8
85#define VNDR_IE_VSIE_OFFSET 12
86#define VNDR_IE_HDR_SIZE 12
87#define VNDR_IE_BEACON_FLAG 0x1
88#define VNDR_IE_PRBRSP_FLAG 0x2
89#define MAX_VNDR_IE_NUMBER 5
90
91#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
92#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020093
Arend van Spriel5b435de2011-10-05 13:19:03 +020094#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
95 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
96
Arend van Spriel5b435de2011-10-05 13:19:03 +020097static u32 brcmf_dbg_level = WL_DBG_ERR;
98
Arend van Sprielce81e312012-10-22 13:55:37 -070099static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200100{
Arend van Sprielc1179032012-10-22 13:55:33 -0700101 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
102 WL_INFO("device is not ready : status (%lu)\n",
103 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200104 return false;
105 }
106 return true;
107}
108
109#define CHAN2G(_channel, _freq, _flags) { \
110 .band = IEEE80211_BAND_2GHZ, \
111 .center_freq = (_freq), \
112 .hw_value = (_channel), \
113 .flags = (_flags), \
114 .max_antenna_gain = 0, \
115 .max_power = 30, \
116}
117
118#define CHAN5G(_channel, _flags) { \
119 .band = IEEE80211_BAND_5GHZ, \
120 .center_freq = 5000 + (5 * (_channel)), \
121 .hw_value = (_channel), \
122 .flags = (_flags), \
123 .max_antenna_gain = 0, \
124 .max_power = 30, \
125}
126
127#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
128#define RATETAB_ENT(_rateid, _flags) \
129 { \
130 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
131 .hw_value = (_rateid), \
132 .flags = (_flags), \
133 }
134
135static struct ieee80211_rate __wl_rates[] = {
136 RATETAB_ENT(BRCM_RATE_1M, 0),
137 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
138 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
139 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
140 RATETAB_ENT(BRCM_RATE_6M, 0),
141 RATETAB_ENT(BRCM_RATE_9M, 0),
142 RATETAB_ENT(BRCM_RATE_12M, 0),
143 RATETAB_ENT(BRCM_RATE_18M, 0),
144 RATETAB_ENT(BRCM_RATE_24M, 0),
145 RATETAB_ENT(BRCM_RATE_36M, 0),
146 RATETAB_ENT(BRCM_RATE_48M, 0),
147 RATETAB_ENT(BRCM_RATE_54M, 0),
148};
149
150#define wl_a_rates (__wl_rates + 4)
151#define wl_a_rates_size 8
152#define wl_g_rates (__wl_rates + 0)
153#define wl_g_rates_size 12
154
155static struct ieee80211_channel __wl_2ghz_channels[] = {
156 CHAN2G(1, 2412, 0),
157 CHAN2G(2, 2417, 0),
158 CHAN2G(3, 2422, 0),
159 CHAN2G(4, 2427, 0),
160 CHAN2G(5, 2432, 0),
161 CHAN2G(6, 2437, 0),
162 CHAN2G(7, 2442, 0),
163 CHAN2G(8, 2447, 0),
164 CHAN2G(9, 2452, 0),
165 CHAN2G(10, 2457, 0),
166 CHAN2G(11, 2462, 0),
167 CHAN2G(12, 2467, 0),
168 CHAN2G(13, 2472, 0),
169 CHAN2G(14, 2484, 0),
170};
171
172static struct ieee80211_channel __wl_5ghz_a_channels[] = {
173 CHAN5G(34, 0), CHAN5G(36, 0),
174 CHAN5G(38, 0), CHAN5G(40, 0),
175 CHAN5G(42, 0), CHAN5G(44, 0),
176 CHAN5G(46, 0), CHAN5G(48, 0),
177 CHAN5G(52, 0), CHAN5G(56, 0),
178 CHAN5G(60, 0), CHAN5G(64, 0),
179 CHAN5G(100, 0), CHAN5G(104, 0),
180 CHAN5G(108, 0), CHAN5G(112, 0),
181 CHAN5G(116, 0), CHAN5G(120, 0),
182 CHAN5G(124, 0), CHAN5G(128, 0),
183 CHAN5G(132, 0), CHAN5G(136, 0),
184 CHAN5G(140, 0), CHAN5G(149, 0),
185 CHAN5G(153, 0), CHAN5G(157, 0),
186 CHAN5G(161, 0), CHAN5G(165, 0),
187 CHAN5G(184, 0), CHAN5G(188, 0),
188 CHAN5G(192, 0), CHAN5G(196, 0),
189 CHAN5G(200, 0), CHAN5G(204, 0),
190 CHAN5G(208, 0), CHAN5G(212, 0),
191 CHAN5G(216, 0),
192};
193
194static struct ieee80211_channel __wl_5ghz_n_channels[] = {
195 CHAN5G(32, 0), CHAN5G(34, 0),
196 CHAN5G(36, 0), CHAN5G(38, 0),
197 CHAN5G(40, 0), CHAN5G(42, 0),
198 CHAN5G(44, 0), CHAN5G(46, 0),
199 CHAN5G(48, 0), CHAN5G(50, 0),
200 CHAN5G(52, 0), CHAN5G(54, 0),
201 CHAN5G(56, 0), CHAN5G(58, 0),
202 CHAN5G(60, 0), CHAN5G(62, 0),
203 CHAN5G(64, 0), CHAN5G(66, 0),
204 CHAN5G(68, 0), CHAN5G(70, 0),
205 CHAN5G(72, 0), CHAN5G(74, 0),
206 CHAN5G(76, 0), CHAN5G(78, 0),
207 CHAN5G(80, 0), CHAN5G(82, 0),
208 CHAN5G(84, 0), CHAN5G(86, 0),
209 CHAN5G(88, 0), CHAN5G(90, 0),
210 CHAN5G(92, 0), CHAN5G(94, 0),
211 CHAN5G(96, 0), CHAN5G(98, 0),
212 CHAN5G(100, 0), CHAN5G(102, 0),
213 CHAN5G(104, 0), CHAN5G(106, 0),
214 CHAN5G(108, 0), CHAN5G(110, 0),
215 CHAN5G(112, 0), CHAN5G(114, 0),
216 CHAN5G(116, 0), CHAN5G(118, 0),
217 CHAN5G(120, 0), CHAN5G(122, 0),
218 CHAN5G(124, 0), CHAN5G(126, 0),
219 CHAN5G(128, 0), CHAN5G(130, 0),
220 CHAN5G(132, 0), CHAN5G(134, 0),
221 CHAN5G(136, 0), CHAN5G(138, 0),
222 CHAN5G(140, 0), CHAN5G(142, 0),
223 CHAN5G(144, 0), CHAN5G(145, 0),
224 CHAN5G(146, 0), CHAN5G(147, 0),
225 CHAN5G(148, 0), CHAN5G(149, 0),
226 CHAN5G(150, 0), CHAN5G(151, 0),
227 CHAN5G(152, 0), CHAN5G(153, 0),
228 CHAN5G(154, 0), CHAN5G(155, 0),
229 CHAN5G(156, 0), CHAN5G(157, 0),
230 CHAN5G(158, 0), CHAN5G(159, 0),
231 CHAN5G(160, 0), CHAN5G(161, 0),
232 CHAN5G(162, 0), CHAN5G(163, 0),
233 CHAN5G(164, 0), CHAN5G(165, 0),
234 CHAN5G(166, 0), CHAN5G(168, 0),
235 CHAN5G(170, 0), CHAN5G(172, 0),
236 CHAN5G(174, 0), CHAN5G(176, 0),
237 CHAN5G(178, 0), CHAN5G(180, 0),
238 CHAN5G(182, 0), CHAN5G(184, 0),
239 CHAN5G(186, 0), CHAN5G(188, 0),
240 CHAN5G(190, 0), CHAN5G(192, 0),
241 CHAN5G(194, 0), CHAN5G(196, 0),
242 CHAN5G(198, 0), CHAN5G(200, 0),
243 CHAN5G(202, 0), CHAN5G(204, 0),
244 CHAN5G(206, 0), CHAN5G(208, 0),
245 CHAN5G(210, 0), CHAN5G(212, 0),
246 CHAN5G(214, 0), CHAN5G(216, 0),
247 CHAN5G(218, 0), CHAN5G(220, 0),
248 CHAN5G(222, 0), CHAN5G(224, 0),
249 CHAN5G(226, 0), CHAN5G(228, 0),
250};
251
252static struct ieee80211_supported_band __wl_band_2ghz = {
253 .band = IEEE80211_BAND_2GHZ,
254 .channels = __wl_2ghz_channels,
255 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
256 .bitrates = wl_g_rates,
257 .n_bitrates = wl_g_rates_size,
258};
259
260static struct ieee80211_supported_band __wl_band_5ghz_a = {
261 .band = IEEE80211_BAND_5GHZ,
262 .channels = __wl_5ghz_a_channels,
263 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
264 .bitrates = wl_a_rates,
265 .n_bitrates = wl_a_rates_size,
266};
267
268static struct ieee80211_supported_band __wl_band_5ghz_n = {
269 .band = IEEE80211_BAND_5GHZ,
270 .channels = __wl_5ghz_n_channels,
271 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
272 .bitrates = wl_a_rates,
273 .n_bitrates = wl_a_rates_size,
274};
275
276static const u32 __wl_cipher_suites[] = {
277 WLAN_CIPHER_SUITE_WEP40,
278 WLAN_CIPHER_SUITE_WEP104,
279 WLAN_CIPHER_SUITE_TKIP,
280 WLAN_CIPHER_SUITE_CCMP,
281 WLAN_CIPHER_SUITE_AES_CMAC,
282};
283
Alwin Beukersf8e4b412011-10-12 20:51:28 +0200284/* tag_ID/length/value_buffer tuple */
285struct brcmf_tlv {
286 u8 id;
287 u8 len;
288 u8 data[1];
289};
290
Hante Meuleman1a873342012-09-27 14:17:54 +0200291/* Vendor specific ie. id = 221, oui and type defines exact ie */
292struct brcmf_vs_tlv {
293 u8 id;
294 u8 len;
295 u8 oui[3];
296 u8 oui_type;
297};
298
299struct parsed_vndr_ie_info {
300 u8 *ie_ptr;
301 u32 ie_len; /* total length including id & length field */
302 struct brcmf_vs_tlv vndrie;
303};
304
305struct parsed_vndr_ies {
306 u32 count;
307 struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
308};
309
Alwin Beukersef6ac172011-10-12 20:51:26 +0200310/* Quarter dBm units to mW
311 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
312 * Table is offset so the last entry is largest mW value that fits in
313 * a u16.
314 */
315
316#define QDBM_OFFSET 153 /* Offset for first entry */
317#define QDBM_TABLE_LEN 40 /* Table size */
318
319/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
320 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
321 */
322#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
323
324/* Largest mW value that will round down to the last table entry,
325 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
326 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
327 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
328 */
329#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
330
331static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
332/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
333/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
334/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
335/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
336/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
337/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
338};
339
340static u16 brcmf_qdbm_to_mw(u8 qdbm)
341{
342 uint factor = 1;
343 int idx = qdbm - QDBM_OFFSET;
344
345 if (idx >= QDBM_TABLE_LEN)
346 /* clamp to max u16 mW value */
347 return 0xFFFF;
348
349 /* scale the qdBm index up to the range of the table 0-40
350 * where an offset of 40 qdBm equals a factor of 10 mW.
351 */
352 while (idx < 0) {
353 idx += 40;
354 factor *= 10;
355 }
356
357 /* return the mW value scaled down to the correct factor of 10,
358 * adding in factor/2 to get proper rounding.
359 */
360 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
361}
362
363static u8 brcmf_mw_to_qdbm(u16 mw)
364{
365 u8 qdbm;
366 int offset;
367 uint mw_uint = mw;
368 uint boundary;
369
370 /* handle boundary case */
371 if (mw_uint <= 1)
372 return 0;
373
374 offset = QDBM_OFFSET;
375
376 /* move mw into the range of the table */
377 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
378 mw_uint *= 10;
379 offset -= 40;
380 }
381
382 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
383 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
384 nqdBm_to_mW_map[qdbm]) / 2;
385 if (mw_uint < boundary)
386 break;
387 }
388
389 qdbm += (u8) offset;
390
391 return qdbm;
392}
393
Arend van Spriel6e186162012-10-22 10:36:22 -0700394static u16 channel_to_chanspec(struct ieee80211_channel *ch)
395{
396 u16 chanspec;
397
398 chanspec = ieee80211_frequency_to_channel(ch->center_freq);
399 chanspec &= WL_CHANSPEC_CHAN_MASK;
400
401 if (ch->band == IEEE80211_BAND_2GHZ)
402 chanspec |= WL_CHANSPEC_BAND_2G;
403 else
404 chanspec |= WL_CHANSPEC_BAND_5G;
405
406 if (ch->flags & IEEE80211_CHAN_NO_HT40) {
407 chanspec |= WL_CHANSPEC_BW_20;
408 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
409 } else {
410 chanspec |= WL_CHANSPEC_BW_40;
411 if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
412 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
413 else
414 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
415 }
416 return chanspec;
417}
418
Arend van Spriel5b435de2011-10-05 13:19:03 +0200419static void convert_key_from_CPU(struct brcmf_wsec_key *key,
420 struct brcmf_wsec_key_le *key_le)
421{
422 key_le->index = cpu_to_le32(key->index);
423 key_le->len = cpu_to_le32(key->len);
424 key_le->algo = cpu_to_le32(key->algo);
425 key_le->flags = cpu_to_le32(key->flags);
426 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
427 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
428 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
429 memcpy(key_le->data, key->data, sizeof(key->data));
430 memcpy(key_le->ea, key->ea, sizeof(key->ea));
431}
432
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200433static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700434send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200435{
436 int err;
437 struct brcmf_wsec_key_le key_le;
438
439 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200440
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700441 brcmf_netdev_wait_pend8021x(ndev);
442
Arend van Sprielac24be62012-10-22 10:36:23 -0700443 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700444 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200445
Arend van Spriel5b435de2011-10-05 13:19:03 +0200446 if (err)
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200447 WL_ERR("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200448 return err;
449}
450
451static s32
452brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
453 enum nl80211_iftype type, u32 *flags,
454 struct vif_params *params)
455{
Arend van Sprielc1179032012-10-22 13:55:33 -0700456 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200457 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200458 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200459 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200460 s32 err = 0;
461
Hante Meuleman1a873342012-09-27 14:17:54 +0200462 WL_TRACE("Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200463
464 switch (type) {
465 case NL80211_IFTYPE_MONITOR:
466 case NL80211_IFTYPE_WDS:
467 WL_ERR("type (%d) : currently we do not support this type\n",
468 type);
469 return -EOPNOTSUPP;
470 case NL80211_IFTYPE_ADHOC:
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200471 cfg->conf->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200472 infra = 0;
473 break;
474 case NL80211_IFTYPE_STATION:
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200475 cfg->conf->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200476 infra = 1;
477 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200478 case NL80211_IFTYPE_AP:
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200479 cfg->conf->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200480 ap = 1;
481 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200482 default:
483 err = -EINVAL;
484 goto done;
485 }
486
Hante Meuleman1a873342012-09-27 14:17:54 +0200487 if (ap) {
Arend van Sprielc1179032012-10-22 13:55:33 -0700488 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200489 if (!cfg->ap_info)
490 cfg->ap_info = kzalloc(sizeof(*cfg->ap_info),
491 GFP_KERNEL);
492 if (!cfg->ap_info) {
Hante Meuleman1a873342012-09-27 14:17:54 +0200493 err = -ENOMEM;
494 goto done;
495 }
496 WL_INFO("IF Type = AP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200497 } else {
Arend van Sprielac24be62012-10-22 10:36:23 -0700498 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
499 BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200500 if (err) {
501 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
502 err = -EAGAIN;
503 goto done;
504 }
505 WL_INFO("IF Type = %s\n",
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200506 (cfg->conf->mode == WL_MODE_IBSS) ?
Hante Meuleman1a873342012-09-27 14:17:54 +0200507 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200508 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200509 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200510
511done:
512 WL_TRACE("Exit\n");
513
514 return err;
515}
516
Arend van Spriel5b435de2011-10-05 13:19:03 +0200517static void brcmf_set_mpc(struct net_device *ndev, int mpc)
518{
Arend van Sprielc1179032012-10-22 13:55:33 -0700519 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200520 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200521
Arend van Sprielce81e312012-10-22 13:55:37 -0700522 if (check_vif_up(ifp->vif)) {
Arend van Sprielc1179032012-10-22 13:55:33 -0700523 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200524 if (err) {
525 WL_ERR("fail to set mpc\n");
526 return;
527 }
528 WL_INFO("MPC : %d\n", mpc);
529 }
530}
531
Hante Meuleman35aafa92012-09-11 21:18:49 +0200532static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le,
533 struct brcmf_ssid *ssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200534{
Arend van Sprielba40d162012-10-22 13:55:38 -0700535 memset(params_le->bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200536 params_le->bss_type = DOT11_BSSTYPE_ANY;
537 params_le->scan_type = 0;
538 params_le->channel_num = 0;
539 params_le->nprobes = cpu_to_le32(-1);
540 params_le->active_time = cpu_to_le32(-1);
541 params_le->passive_time = cpu_to_le32(-1);
542 params_le->home_time = cpu_to_le32(-1);
Hante Meulemaned205b32012-09-11 21:16:47 +0200543 if (ssid && ssid->SSID_len) {
544 params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len);
545 memcpy(&params_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len);
546 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200547}
548
549static s32
Arend van Spriel5b435de2011-10-05 13:19:03 +0200550brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
551 struct brcmf_ssid *ssid, u16 action)
552{
553 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
554 offsetof(struct brcmf_iscan_params_le, params_le);
555 struct brcmf_iscan_params_le *params;
556 s32 err = 0;
557
558 if (ssid && ssid->SSID_len)
559 params_size += sizeof(struct brcmf_ssid);
560 params = kzalloc(params_size, GFP_KERNEL);
561 if (!params)
562 return -ENOMEM;
563 BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
564
Hante Meuleman35aafa92012-09-11 21:18:49 +0200565 brcmf_iscan_prep(&params->params_le, ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200566
567 params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
568 params->action = cpu_to_le16(action);
569 params->scan_duration = cpu_to_le16(0);
570
Arend van Sprielac24be62012-10-22 10:36:23 -0700571 err = brcmf_fil_iovar_data_set(netdev_priv(iscan->ndev), "iscan",
572 params, params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200573 if (err) {
574 if (err == -EBUSY)
575 WL_INFO("system busy : iscan canceled\n");
576 else
577 WL_ERR("error (%d)\n", err);
578 }
579
580 kfree(params);
581 return err;
582}
583
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200584static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200585{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200586 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
587 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200588 struct brcmf_ssid ssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700589 u32 passive_scan;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200590 s32 err = 0;
591
592 /* Broadcast scan by default */
593 memset(&ssid, 0, sizeof(ssid));
594
595 iscan->state = WL_ISCAN_STATE_SCANING;
596
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700597 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700598 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700599 BRCMF_C_SET_PASSIVE_SCAN, passive_scan);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200600 if (err) {
601 WL_ERR("error (%d)\n", err);
602 return err;
603 }
604 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200605 cfg->iscan_kickstart = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200606 err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
607 if (err) {
608 brcmf_set_mpc(ndev, 1);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200609 cfg->iscan_kickstart = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200610 return err;
611 }
612 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
613 iscan->timer_on = 1;
614 return err;
615}
616
617static s32
Hante Meuleman35aafa92012-09-11 21:18:49 +0200618brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
619 struct cfg80211_scan_request *request,
620 struct cfg80211_ssid *this_ssid)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200621{
Arend van Sprielc1179032012-10-22 13:55:33 -0700622 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200623 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200624 struct cfg80211_ssid *ssids;
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200625 struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700626 u32 passive_scan;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200627 bool iscan_req;
628 bool spec_scan;
629 s32 err = 0;
630 u32 SSID_len;
631
Arend van Sprielc1179032012-10-22 13:55:33 -0700632 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
633 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200634 return -EAGAIN;
635 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700636 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
637 WL_ERR("Scanning being aborted: status (%lu)\n",
638 cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200639 return -EAGAIN;
640 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700641 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
642 WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200643 return -EAGAIN;
644 }
645
646 iscan_req = false;
647 spec_scan = false;
648 if (request) {
649 /* scan bss */
650 ssids = request->ssids;
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200651 if (cfg->iscan_on && (!ssids || !ssids->ssid_len))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200652 iscan_req = true;
653 } else {
654 /* scan in ibss */
655 /* we don't do iscan in ibss */
656 ssids = this_ssid;
657 }
658
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200659 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700660 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200661 if (iscan_req) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200662 err = brcmf_do_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200663 if (!err)
664 return err;
665 else
666 goto scan_out;
667 } else {
668 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
669 ssids->ssid, ssids->ssid_len);
670 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
671 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
672 sr->ssid_le.SSID_len = cpu_to_le32(0);
673 if (SSID_len) {
674 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
675 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
676 spec_scan = true;
677 } else {
678 WL_SCAN("Broadcast scan\n");
679 }
680
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700681 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700682 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700683 passive_scan);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200684 if (err) {
685 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
686 goto scan_out;
687 }
688 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700689 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700690 &sr->ssid_le, sizeof(sr->ssid_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +0200691 if (err) {
692 if (err == -EBUSY)
693 WL_INFO("system busy : scan for \"%s\" "
694 "canceled\n", sr->ssid_le.SSID);
695 else
696 WL_ERR("WLC_SCAN error (%d)\n", err);
697
698 brcmf_set_mpc(ndev, 1);
699 goto scan_out;
700 }
701 }
702
703 return 0;
704
705scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700706 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200707 cfg->scan_request = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200708 return err;
709}
710
Hante Meulemane756af52012-09-11 21:18:52 +0200711static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
712 struct cfg80211_scan_request *request)
713{
714 u32 n_ssids;
715 u32 n_channels;
716 s32 i;
717 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200718 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200719 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200720 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200721
Arend van Sprielba40d162012-10-22 13:55:38 -0700722 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200723 params_le->bss_type = DOT11_BSSTYPE_ANY;
724 params_le->scan_type = 0;
725 params_le->channel_num = 0;
726 params_le->nprobes = cpu_to_le32(-1);
727 params_le->active_time = cpu_to_le32(-1);
728 params_le->passive_time = cpu_to_le32(-1);
729 params_le->home_time = cpu_to_le32(-1);
730 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
731
732 /* if request is null exit so it will be all channel broadcast scan */
733 if (!request)
734 return;
735
736 n_ssids = request->n_ssids;
737 n_channels = request->n_channels;
738 /* Copy channel array if applicable */
739 WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels);
740 if (n_channels > 0) {
741 for (i = 0; i < n_channels; i++) {
Arend van Spriel6e186162012-10-22 10:36:22 -0700742 chanspec = channel_to_chanspec(request->channels[i]);
Hante Meulemane756af52012-09-11 21:18:52 +0200743 WL_SCAN("Chan : %d, Channel spec: %x\n",
Arend van Spriel6e186162012-10-22 10:36:22 -0700744 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200745 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200746 }
747 } else {
748 WL_SCAN("Scanning all channels\n");
749 }
750 /* Copy ssid array if applicable */
751 WL_SCAN("### List of SSIDs to scan ### %d\n", n_ssids);
752 if (n_ssids > 0) {
753 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
754 n_channels * sizeof(u16);
755 offset = roundup(offset, sizeof(u32));
756 ptr = (char *)params_le + offset;
757 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200758 memset(&ssid_le, 0, sizeof(ssid_le));
759 ssid_le.SSID_len =
760 cpu_to_le32(request->ssids[i].ssid_len);
761 memcpy(ssid_le.SSID, request->ssids[i].ssid,
762 request->ssids[i].ssid_len);
763 if (!ssid_le.SSID_len)
Hante Meulemane756af52012-09-11 21:18:52 +0200764 WL_SCAN("%d: Broadcast scan\n", i);
765 else
766 WL_SCAN("%d: scan for %s size =%d\n", i,
Arend van Spriel029591f2012-09-19 22:21:06 +0200767 ssid_le.SSID, ssid_le.SSID_len);
768 memcpy(ptr, &ssid_le, sizeof(ssid_le));
769 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200770 }
771 } else {
772 WL_SCAN("Broadcast scan %p\n", request->ssids);
773 if ((request->ssids) && request->ssids->ssid_len) {
774 WL_SCAN("SSID %s len=%d\n", params_le->ssid_le.SSID,
775 request->ssids->ssid_len);
776 params_le->ssid_le.SSID_len =
777 cpu_to_le32(request->ssids->ssid_len);
778 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
779 request->ssids->ssid_len);
780 }
781 }
782 /* Adding mask to channel numbers */
783 params_le->channel_num =
784 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
785 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
786}
787
788static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200789brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
Hante Meulemane756af52012-09-11 21:18:52 +0200790 struct net_device *ndev,
791 bool aborted, bool fw_abort)
792{
793 struct brcmf_scan_params_le params_le;
794 struct cfg80211_scan_request *scan_request;
795 s32 err = 0;
796
797 WL_SCAN("Enter\n");
798
799 /* clear scan request, because the FW abort can cause a second call */
800 /* to this functon and might cause a double cfg80211_scan_done */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200801 scan_request = cfg->scan_request;
802 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200803
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200804 if (timer_pending(&cfg->escan_timeout))
805 del_timer_sync(&cfg->escan_timeout);
Hante Meulemane756af52012-09-11 21:18:52 +0200806
807 if (fw_abort) {
808 /* Do a scan abort to stop the driver's scan engine */
809 WL_SCAN("ABORT scan in firmware\n");
810 memset(&params_le, 0, sizeof(params_le));
Arend van Sprielba40d162012-10-22 13:55:38 -0700811 memset(params_le.bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200812 params_le.bss_type = DOT11_BSSTYPE_ANY;
813 params_le.scan_type = 0;
814 params_le.channel_num = cpu_to_le32(1);
815 params_le.nprobes = cpu_to_le32(1);
816 params_le.active_time = cpu_to_le32(-1);
817 params_le.passive_time = cpu_to_le32(-1);
818 params_le.home_time = cpu_to_le32(-1);
819 /* Scan is aborted by setting channel_list[0] to -1 */
820 params_le.channel_list[0] = cpu_to_le16(-1);
821 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielac24be62012-10-22 10:36:23 -0700822 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
823 &params_le, sizeof(params_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200824 if (err)
825 WL_ERR("Scan abort failed\n");
826 }
Arend van Spriele5806072012-09-19 22:21:08 +0200827 /*
828 * e-scan can be initiated by scheduled scan
829 * which takes precedence.
830 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200831 if (cfg->sched_escan) {
Arend van Spriele5806072012-09-19 22:21:08 +0200832 WL_SCAN("scheduled scan completed\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200833 cfg->sched_escan = false;
Arend van Spriele5806072012-09-19 22:21:08 +0200834 if (!aborted)
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200835 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriele5806072012-09-19 22:21:08 +0200836 brcmf_set_mpc(ndev, 1);
837 } else if (scan_request) {
Hante Meulemane756af52012-09-11 21:18:52 +0200838 WL_SCAN("ESCAN Completed scan: %s\n",
839 aborted ? "Aborted" : "Done");
840 cfg80211_scan_done(scan_request, aborted);
841 brcmf_set_mpc(ndev, 1);
842 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700843 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meulemane756af52012-09-11 21:18:52 +0200844 WL_ERR("Scan complete while device not scanning\n");
845 return -EPERM;
846 }
847
848 return err;
849}
850
851static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200852brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
Hante Meulemane756af52012-09-11 21:18:52 +0200853 struct cfg80211_scan_request *request, u16 action)
854{
855 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
856 offsetof(struct brcmf_escan_params_le, params_le);
857 struct brcmf_escan_params_le *params;
858 s32 err = 0;
859
860 WL_SCAN("E-SCAN START\n");
861
862 if (request != NULL) {
863 /* Allocate space for populating ssids in struct */
864 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
865
866 /* Allocate space for populating ssids in struct */
867 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
868 }
869
870 params = kzalloc(params_size, GFP_KERNEL);
871 if (!params) {
872 err = -ENOMEM;
873 goto exit;
874 }
875 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
876 brcmf_escan_prep(&params->params_le, request);
877 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
878 params->action = cpu_to_le16(action);
879 params->sync_id = cpu_to_le16(0x1234);
880
Arend van Sprielac24be62012-10-22 10:36:23 -0700881 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
882 params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200883 if (err) {
884 if (err == -EBUSY)
885 WL_INFO("system busy : escan canceled\n");
886 else
887 WL_ERR("error (%d)\n", err);
888 }
889
890 kfree(params);
891exit:
892 return err;
893}
894
895static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200896brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Hante Meulemane756af52012-09-11 21:18:52 +0200897 struct net_device *ndev, struct cfg80211_scan_request *request)
898{
899 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700900 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200901 struct brcmf_scan_results *results;
902
903 WL_SCAN("Enter\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200904 cfg->escan_info.ndev = ndev;
905 cfg->escan_info.wiphy = wiphy;
906 cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700907 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700908 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700909 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200910 if (err) {
911 WL_ERR("error (%d)\n", err);
912 return err;
913 }
914 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200915 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200916 results->version = 0;
917 results->count = 0;
918 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
919
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200920 err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200921 if (err)
922 brcmf_set_mpc(ndev, 1);
923 return err;
924}
925
926static s32
927brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
928 struct cfg80211_scan_request *request,
929 struct cfg80211_ssid *this_ssid)
930{
Arend van Sprielc1179032012-10-22 13:55:33 -0700931 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200932 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Hante Meulemane756af52012-09-11 21:18:52 +0200933 struct cfg80211_ssid *ssids;
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200934 struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700935 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200936 bool escan_req;
937 bool spec_scan;
938 s32 err;
939 u32 SSID_len;
940
941 WL_SCAN("START ESCAN\n");
942
Arend van Sprielc1179032012-10-22 13:55:33 -0700943 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
944 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200945 return -EAGAIN;
946 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700947 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
948 WL_ERR("Scanning being aborted: status (%lu)\n",
949 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200950 return -EAGAIN;
951 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700952 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
953 WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200954 return -EAGAIN;
955 }
956
957 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200958 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200959 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
960
961 escan_req = false;
962 if (request) {
963 /* scan bss */
964 ssids = request->ssids;
965 escan_req = true;
966 } else {
967 /* scan in ibss */
968 /* we don't do escan in ibss */
969 ssids = this_ssid;
970 }
971
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200972 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700973 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200974 if (escan_req) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200975 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Hante Meulemane756af52012-09-11 21:18:52 +0200976 if (!err)
977 return err;
978 else
979 goto scan_out;
980 } else {
981 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
982 ssids->ssid, ssids->ssid_len);
983 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
984 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
985 sr->ssid_le.SSID_len = cpu_to_le32(0);
986 spec_scan = false;
987 if (SSID_len) {
988 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
989 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
990 spec_scan = true;
991 } else
992 WL_SCAN("Broadcast scan\n");
993
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700994 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700995 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700996 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200997 if (err) {
998 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
999 goto scan_out;
1000 }
1001 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -07001002 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -07001003 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +02001004 if (err) {
1005 if (err == -EBUSY)
1006 WL_INFO("BUSY: scan for \"%s\" canceled\n",
1007 sr->ssid_le.SSID);
1008 else
1009 WL_ERR("WLC_SCAN error (%d)\n", err);
1010
1011 brcmf_set_mpc(ndev, 1);
1012 goto scan_out;
1013 }
1014 }
1015
1016 return 0;
1017
1018scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -07001019 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001020 if (timer_pending(&cfg->escan_timeout))
1021 del_timer_sync(&cfg->escan_timeout);
1022 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +02001023 return err;
1024}
1025
Arend van Spriel5b435de2011-10-05 13:19:03 +02001026static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001027brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001028{
Johannes Bergfd014282012-06-18 19:17:03 +02001029 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001030 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001031 s32 err = 0;
1032
1033 WL_TRACE("Enter\n");
1034
Arend van Sprielce81e312012-10-22 13:55:37 -07001035 if (!check_vif_up(container_of(request->wdev,
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001036 struct brcmf_cfg80211_vif, wdev)))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001037 return -EIO;
1038
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001039 if (cfg->iscan_on)
Hante Meulemane756af52012-09-11 21:18:52 +02001040 err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001041 else if (cfg->escan_on)
Hante Meulemane756af52012-09-11 21:18:52 +02001042 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
1043
Arend van Spriel5b435de2011-10-05 13:19:03 +02001044 if (err)
1045 WL_ERR("scan error (%d)\n", err);
1046
1047 WL_TRACE("Exit\n");
1048 return err;
1049}
1050
1051static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
1052{
1053 s32 err = 0;
1054
Arend van Sprielac24be62012-10-22 10:36:23 -07001055 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
1056 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001057 if (err)
1058 WL_ERR("Error (%d)\n", err);
1059
1060 return err;
1061}
1062
1063static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
1064{
1065 s32 err = 0;
1066
Arend van Sprielac24be62012-10-22 10:36:23 -07001067 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
1068 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001069 if (err)
1070 WL_ERR("Error (%d)\n", err);
1071
1072 return err;
1073}
1074
1075static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
1076{
1077 s32 err = 0;
1078 u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
1079
Arend van Sprielac24be62012-10-22 10:36:23 -07001080 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001081 if (err) {
1082 WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
1083 return err;
1084 }
1085 return err;
1086}
1087
1088static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1089{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001090 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1091 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001092 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001093 s32 err = 0;
1094
1095 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001096 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001097 return -EIO;
1098
1099 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001100 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
1101 cfg->conf->rts_threshold = wiphy->rts_threshold;
1102 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001103 if (!err)
1104 goto done;
1105 }
1106 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001107 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
1108 cfg->conf->frag_threshold = wiphy->frag_threshold;
1109 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001110 if (!err)
1111 goto done;
1112 }
1113 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001114 && (cfg->conf->retry_long != wiphy->retry_long)) {
1115 cfg->conf->retry_long = wiphy->retry_long;
1116 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001117 if (!err)
1118 goto done;
1119 }
1120 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001121 && (cfg->conf->retry_short != wiphy->retry_short)) {
1122 cfg->conf->retry_short = wiphy->retry_short;
1123 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001124 if (!err)
1125 goto done;
1126 }
1127
1128done:
1129 WL_TRACE("Exit\n");
1130 return err;
1131}
1132
Arend van Spriel5b435de2011-10-05 13:19:03 +02001133static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
1134{
1135 memset(prof, 0, sizeof(*prof));
1136}
1137
1138static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
1139 size_t *join_params_size)
1140{
1141 u16 chanspec = 0;
1142
1143 if (ch != 0) {
1144 if (ch <= CH_MAX_2G_CHANNEL)
1145 chanspec |= WL_CHANSPEC_BAND_2G;
1146 else
1147 chanspec |= WL_CHANSPEC_BAND_5G;
1148
1149 chanspec |= WL_CHANSPEC_BW_20;
1150 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1151
1152 *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
1153 sizeof(u16);
1154
1155 chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
1156 join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1157 join_params->params_le.chanspec_num = cpu_to_le32(1);
1158
1159 WL_CONN("join_params->params.chanspec_list[0]= %#X,"
1160 "channel %d, chanspec %#X\n",
1161 chanspec, ch, chanspec);
1162 }
1163}
1164
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001165static void brcmf_link_down(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001166{
1167 struct net_device *ndev = NULL;
1168 s32 err = 0;
1169
1170 WL_TRACE("Enter\n");
1171
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001172 if (cfg->link_up) {
1173 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001174 WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Sprielac24be62012-10-22 10:36:23 -07001175 err = brcmf_fil_cmd_data_set(netdev_priv(ndev),
1176 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001177 if (err)
1178 WL_ERR("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001179 cfg->link_up = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001180 }
1181 WL_TRACE("Exit\n");
1182}
1183
1184static s32
1185brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1186 struct cfg80211_ibss_params *params)
1187{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001188 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001189 struct brcmf_if *ifp = netdev_priv(ndev);
1190 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001191 struct brcmf_join_params join_params;
1192 size_t join_params_size = 0;
1193 s32 err = 0;
1194 s32 wsec = 0;
1195 s32 bcnprd;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001196
1197 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001198 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 return -EIO;
1200
1201 if (params->ssid)
1202 WL_CONN("SSID: %s\n", params->ssid);
1203 else {
1204 WL_CONN("SSID: NULL, Not supported\n");
1205 return -EOPNOTSUPP;
1206 }
1207
Arend van Sprielc1179032012-10-22 13:55:33 -07001208 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001209
1210 if (params->bssid)
Andy Shevchenko040a7832012-07-12 10:43:44 +03001211 WL_CONN("BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001212 else
1213 WL_CONN("No BSSID specified\n");
1214
1215 if (params->channel)
1216 WL_CONN("channel: %d\n", params->channel->center_freq);
1217 else
1218 WL_CONN("no channel specified\n");
1219
1220 if (params->channel_fixed)
1221 WL_CONN("fixed channel required\n");
1222 else
1223 WL_CONN("no fixed channel required\n");
1224
1225 if (params->ie && params->ie_len)
1226 WL_CONN("ie len: %d\n", params->ie_len);
1227 else
1228 WL_CONN("no ie specified\n");
1229
1230 if (params->beacon_interval)
1231 WL_CONN("beacon interval: %d\n", params->beacon_interval);
1232 else
1233 WL_CONN("no beacon interval specified\n");
1234
1235 if (params->basic_rates)
1236 WL_CONN("basic rates: %08X\n", params->basic_rates);
1237 else
1238 WL_CONN("no basic rates specified\n");
1239
1240 if (params->privacy)
1241 WL_CONN("privacy required\n");
1242 else
1243 WL_CONN("no privacy required\n");
1244
1245 /* Configure Privacy for starter */
1246 if (params->privacy)
1247 wsec |= WEP_ENABLED;
1248
Arend van Sprielc1179032012-10-22 13:55:33 -07001249 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250 if (err) {
1251 WL_ERR("wsec failed (%d)\n", err);
1252 goto done;
1253 }
1254
1255 /* Configure Beacon Interval for starter */
1256 if (params->beacon_interval)
1257 bcnprd = params->beacon_interval;
1258 else
1259 bcnprd = 100;
1260
Arend van Sprielc1179032012-10-22 13:55:33 -07001261 err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262 if (err) {
1263 WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
1264 goto done;
1265 }
1266
1267 /* Configure required join parameter */
1268 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1269
1270 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001271 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1272 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1273 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1274 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001276
1277 /* BSSID */
1278 if (params->bssid) {
1279 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1280 join_params_size = sizeof(join_params.ssid_le) +
1281 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001282 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001284 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001285 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001286 }
1287
Arend van Spriel5b435de2011-10-05 13:19:03 +02001288 /* Channel */
1289 if (params->channel) {
1290 u32 target_channel;
1291
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001292 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001293 ieee80211_frequency_to_channel(
1294 params->channel->center_freq);
1295 if (params->channel_fixed) {
1296 /* adding chanspec */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001297 brcmf_ch_to_chanspec(cfg->channel,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001298 &join_params, &join_params_size);
1299 }
1300
1301 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001302 target_channel = cfg->channel;
Arend van Sprielc1179032012-10-22 13:55:33 -07001303 err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001304 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 if (err) {
1306 WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
1307 goto done;
1308 }
1309 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001310 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001311
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001312 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001313
1314
Arend van Sprielc1179032012-10-22 13:55:33 -07001315 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001316 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001317 if (err) {
1318 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1319 goto done;
1320 }
1321
1322done:
1323 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001324 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001325 WL_TRACE("Exit\n");
1326 return err;
1327}
1328
1329static s32
1330brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1331{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001332 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001333 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001334 s32 err = 0;
1335
1336 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001337 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001338 return -EIO;
1339
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001340 brcmf_link_down(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001341
1342 WL_TRACE("Exit\n");
1343
1344 return err;
1345}
1346
1347static s32 brcmf_set_wpa_version(struct net_device *ndev,
1348 struct cfg80211_connect_params *sme)
1349{
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 s32 val = 0;
1353 s32 err = 0;
1354
1355 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1356 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1357 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1358 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1359 else
1360 val = WPA_AUTH_DISABLED;
1361 WL_CONN("setting wpa_auth to 0x%0x\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001362 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001363 if (err) {
1364 WL_ERR("set wpa_auth failed (%d)\n", err);
1365 return err;
1366 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001367 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001368 sec->wpa_versions = sme->crypto.wpa_versions;
1369 return err;
1370}
1371
1372static s32 brcmf_set_auth_type(struct net_device *ndev,
1373 struct cfg80211_connect_params *sme)
1374{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001375 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001376 struct brcmf_cfg80211_security *sec;
1377 s32 val = 0;
1378 s32 err = 0;
1379
1380 switch (sme->auth_type) {
1381 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1382 val = 0;
1383 WL_CONN("open system\n");
1384 break;
1385 case NL80211_AUTHTYPE_SHARED_KEY:
1386 val = 1;
1387 WL_CONN("shared key\n");
1388 break;
1389 case NL80211_AUTHTYPE_AUTOMATIC:
1390 val = 2;
1391 WL_CONN("automatic\n");
1392 break;
1393 case NL80211_AUTHTYPE_NETWORK_EAP:
1394 WL_CONN("network eap\n");
1395 default:
1396 val = 2;
1397 WL_ERR("invalid auth type (%d)\n", sme->auth_type);
1398 break;
1399 }
1400
Arend van Sprielac24be62012-10-22 10:36:23 -07001401 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001402 if (err) {
1403 WL_ERR("set auth failed (%d)\n", err);
1404 return err;
1405 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001406 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001407 sec->auth_type = sme->auth_type;
1408 return err;
1409}
1410
1411static s32
1412brcmf_set_set_cipher(struct net_device *ndev,
1413 struct cfg80211_connect_params *sme)
1414{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001415 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001416 struct brcmf_cfg80211_security *sec;
1417 s32 pval = 0;
1418 s32 gval = 0;
1419 s32 err = 0;
1420
1421 if (sme->crypto.n_ciphers_pairwise) {
1422 switch (sme->crypto.ciphers_pairwise[0]) {
1423 case WLAN_CIPHER_SUITE_WEP40:
1424 case WLAN_CIPHER_SUITE_WEP104:
1425 pval = WEP_ENABLED;
1426 break;
1427 case WLAN_CIPHER_SUITE_TKIP:
1428 pval = TKIP_ENABLED;
1429 break;
1430 case WLAN_CIPHER_SUITE_CCMP:
1431 pval = AES_ENABLED;
1432 break;
1433 case WLAN_CIPHER_SUITE_AES_CMAC:
1434 pval = AES_ENABLED;
1435 break;
1436 default:
1437 WL_ERR("invalid cipher pairwise (%d)\n",
1438 sme->crypto.ciphers_pairwise[0]);
1439 return -EINVAL;
1440 }
1441 }
1442 if (sme->crypto.cipher_group) {
1443 switch (sme->crypto.cipher_group) {
1444 case WLAN_CIPHER_SUITE_WEP40:
1445 case WLAN_CIPHER_SUITE_WEP104:
1446 gval = WEP_ENABLED;
1447 break;
1448 case WLAN_CIPHER_SUITE_TKIP:
1449 gval = TKIP_ENABLED;
1450 break;
1451 case WLAN_CIPHER_SUITE_CCMP:
1452 gval = AES_ENABLED;
1453 break;
1454 case WLAN_CIPHER_SUITE_AES_CMAC:
1455 gval = AES_ENABLED;
1456 break;
1457 default:
1458 WL_ERR("invalid cipher group (%d)\n",
1459 sme->crypto.cipher_group);
1460 return -EINVAL;
1461 }
1462 }
1463
1464 WL_CONN("pval (%d) gval (%d)\n", pval, gval);
Arend van Sprielac24be62012-10-22 10:36:23 -07001465 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466 if (err) {
1467 WL_ERR("error (%d)\n", err);
1468 return err;
1469 }
1470
Arend van Spriel06bb1232012-09-27 14:17:56 +02001471 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001472 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1473 sec->cipher_group = sme->crypto.cipher_group;
1474
1475 return err;
1476}
1477
1478static s32
1479brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1480{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001481 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482 struct brcmf_cfg80211_security *sec;
1483 s32 val = 0;
1484 s32 err = 0;
1485
1486 if (sme->crypto.n_akm_suites) {
Arend van Sprielac24be62012-10-22 10:36:23 -07001487 err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
1488 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001489 if (err) {
1490 WL_ERR("could not get wpa_auth (%d)\n", err);
1491 return err;
1492 }
1493 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1494 switch (sme->crypto.akm_suites[0]) {
1495 case WLAN_AKM_SUITE_8021X:
1496 val = WPA_AUTH_UNSPECIFIED;
1497 break;
1498 case WLAN_AKM_SUITE_PSK:
1499 val = WPA_AUTH_PSK;
1500 break;
1501 default:
1502 WL_ERR("invalid cipher group (%d)\n",
1503 sme->crypto.cipher_group);
1504 return -EINVAL;
1505 }
1506 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1507 switch (sme->crypto.akm_suites[0]) {
1508 case WLAN_AKM_SUITE_8021X:
1509 val = WPA2_AUTH_UNSPECIFIED;
1510 break;
1511 case WLAN_AKM_SUITE_PSK:
1512 val = WPA2_AUTH_PSK;
1513 break;
1514 default:
1515 WL_ERR("invalid cipher group (%d)\n",
1516 sme->crypto.cipher_group);
1517 return -EINVAL;
1518 }
1519 }
1520
1521 WL_CONN("setting wpa_auth to %d\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001522 err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
1523 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524 if (err) {
1525 WL_ERR("could not set wpa_auth (%d)\n", err);
1526 return err;
1527 }
1528 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001529 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001530 sec->wpa_auth = sme->crypto.akm_suites[0];
1531
1532 return err;
1533}
1534
1535static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001536brcmf_set_sharedkey(struct net_device *ndev,
1537 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001538{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001539 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001540 struct brcmf_cfg80211_security *sec;
1541 struct brcmf_wsec_key key;
1542 s32 val;
1543 s32 err = 0;
1544
1545 WL_CONN("key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001546
Roland Vossena718e2f2011-10-12 20:51:24 +02001547 if (sme->key_len == 0)
1548 return 0;
1549
Arend van Spriel06bb1232012-09-27 14:17:56 +02001550 sec = &profile->sec;
Roland Vossena718e2f2011-10-12 20:51:24 +02001551 WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n",
1552 sec->wpa_versions, sec->cipher_pairwise);
1553
1554 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1555 return 0;
1556
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001557 if (!(sec->cipher_pairwise &
1558 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1559 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001560
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001561 memset(&key, 0, sizeof(key));
1562 key.len = (u32) sme->key_len;
1563 key.index = (u32) sme->key_idx;
1564 if (key.len > sizeof(key.data)) {
1565 WL_ERR("Too long key length (%u)\n", key.len);
1566 return -EINVAL;
1567 }
1568 memcpy(key.data, sme->key, key.len);
1569 key.flags = BRCMF_PRIMARY_KEY;
1570 switch (sec->cipher_pairwise) {
1571 case WLAN_CIPHER_SUITE_WEP40:
1572 key.algo = CRYPTO_ALGO_WEP1;
1573 break;
1574 case WLAN_CIPHER_SUITE_WEP104:
1575 key.algo = CRYPTO_ALGO_WEP128;
1576 break;
1577 default:
1578 WL_ERR("Invalid algorithm (%d)\n",
1579 sme->crypto.ciphers_pairwise[0]);
1580 return -EINVAL;
1581 }
1582 /* Set the new key/index */
1583 WL_CONN("key length (%d) key index (%d) algo (%d)\n",
1584 key.len, key.index, key.algo);
1585 WL_CONN("key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001586 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001587 if (err)
1588 return err;
1589
1590 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
1591 WL_CONN("set auth_type to shared key\n");
1592 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001593 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001594 if (err)
1595 WL_ERR("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001596 }
1597 return err;
1598}
1599
1600static s32
1601brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1602 struct cfg80211_connect_params *sme)
1603{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001604 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001605 struct brcmf_if *ifp = netdev_priv(ndev);
1606 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001607 struct ieee80211_channel *chan = sme->channel;
1608 struct brcmf_join_params join_params;
1609 size_t join_params_size;
1610 struct brcmf_ssid ssid;
1611
1612 s32 err = 0;
1613
1614 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001615 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001616 return -EIO;
1617
1618 if (!sme->ssid) {
1619 WL_ERR("Invalid ssid\n");
1620 return -EOPNOTSUPP;
1621 }
1622
Arend van Sprielc1179032012-10-22 13:55:33 -07001623 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001624
1625 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001626 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001627 ieee80211_frequency_to_channel(chan->center_freq);
1628 WL_CONN("channel (%d), center_req (%d)\n",
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001629 cfg->channel, chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001630 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001631 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632
1633 WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1634
1635 err = brcmf_set_wpa_version(ndev, sme);
1636 if (err) {
1637 WL_ERR("wl_set_wpa_version failed (%d)\n", err);
1638 goto done;
1639 }
1640
1641 err = brcmf_set_auth_type(ndev, sme);
1642 if (err) {
1643 WL_ERR("wl_set_auth_type failed (%d)\n", err);
1644 goto done;
1645 }
1646
1647 err = brcmf_set_set_cipher(ndev, sme);
1648 if (err) {
1649 WL_ERR("wl_set_set_cipher failed (%d)\n", err);
1650 goto done;
1651 }
1652
1653 err = brcmf_set_key_mgmt(ndev, sme);
1654 if (err) {
1655 WL_ERR("wl_set_key_mgmt failed (%d)\n", err);
1656 goto done;
1657 }
1658
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001659 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001660 if (err) {
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001661 WL_ERR("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001662 goto done;
1663 }
1664
1665 memset(&join_params, 0, sizeof(join_params));
1666 join_params_size = sizeof(join_params.ssid_le);
1667
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001668 profile->ssid.SSID_len = min_t(u32,
1669 sizeof(ssid.SSID), (u32)sme->ssid_len);
1670 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
1671 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1672 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001673
Arend van Sprielba40d162012-10-22 13:55:38 -07001674 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001675
1676 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
1677 WL_CONN("ssid \"%s\", len (%d)\n",
1678 ssid.SSID, ssid.SSID_len);
1679
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001680 brcmf_ch_to_chanspec(cfg->channel,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001681 &join_params, &join_params_size);
Arend van Sprielc1179032012-10-22 13:55:33 -07001682 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001683 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001684 if (err)
1685 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1686
1687done:
1688 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001689 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001690 WL_TRACE("Exit\n");
1691 return err;
1692}
1693
1694static s32
1695brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1696 u16 reason_code)
1697{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001698 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001699 struct brcmf_if *ifp = netdev_priv(ndev);
1700 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001701 struct brcmf_scb_val_le scbval;
1702 s32 err = 0;
1703
1704 WL_TRACE("Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001705 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001706 return -EIO;
1707
Arend van Sprielc1179032012-10-22 13:55:33 -07001708 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001709
Arend van Spriel06bb1232012-09-27 14:17:56 +02001710 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001711 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001712 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001713 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001714 if (err)
1715 WL_ERR("error (%d)\n", err);
1716
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001717 cfg->link_up = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001718
1719 WL_TRACE("Exit\n");
1720 return err;
1721}
1722
1723static s32
1724brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001725 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001726{
1727
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001728 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001729 struct net_device *ndev = cfg_to_ndev(cfg);
1730 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001731 u16 txpwrmw;
1732 s32 err = 0;
1733 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001734 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001735
1736 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001737 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001738 return -EIO;
1739
1740 switch (type) {
1741 case NL80211_TX_POWER_AUTOMATIC:
1742 break;
1743 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001744 case NL80211_TX_POWER_FIXED:
1745 if (dbm < 0) {
1746 WL_ERR("TX_POWER_FIXED - dbm is negative\n");
1747 err = -EINVAL;
1748 goto done;
1749 }
1750 break;
1751 }
1752 /* Make sure radio is off or on as far as software is concerned */
1753 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001754 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001755 if (err)
1756 WL_ERR("WLC_SET_RADIO error (%d)\n", err);
1757
1758 if (dbm > 0xffff)
1759 txpwrmw = 0xffff;
1760 else
1761 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001762 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1763 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001764 if (err)
1765 WL_ERR("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001766 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001767
1768done:
1769 WL_TRACE("Exit\n");
1770 return err;
1771}
1772
1773static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
1774{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001775 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001776 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001777 s32 txpwrdbm;
1778 u8 result;
1779 s32 err = 0;
1780
1781 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001782 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001783 return -EIO;
1784
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001785 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001786 if (err) {
1787 WL_ERR("error (%d)\n", err);
1788 goto done;
1789 }
1790
1791 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001792 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001793
1794done:
1795 WL_TRACE("Exit\n");
1796 return err;
1797}
1798
1799static s32
1800brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1801 u8 key_idx, bool unicast, bool multicast)
1802{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001803 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001804 u32 index;
1805 u32 wsec;
1806 s32 err = 0;
1807
1808 WL_TRACE("Enter\n");
1809 WL_CONN("key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001810 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001811 return -EIO;
1812
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001813 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001814 if (err) {
1815 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1816 goto done;
1817 }
1818
1819 if (wsec & WEP_ENABLED) {
1820 /* Just select a new current key */
1821 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001822 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001823 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001824 if (err)
1825 WL_ERR("error (%d)\n", err);
1826 }
1827done:
1828 WL_TRACE("Exit\n");
1829 return err;
1830}
1831
1832static s32
1833brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1834 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1835{
1836 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001837 s32 err = 0;
1838
1839 memset(&key, 0, sizeof(key));
1840 key.index = (u32) key_idx;
1841 /* Instead of bcast for ea address for default wep keys,
1842 driver needs it to be Null */
1843 if (!is_multicast_ether_addr(mac_addr))
1844 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1845 key.len = (u32) params->key_len;
1846 /* check for key index change */
1847 if (key.len == 0) {
1848 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001849 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001850 if (err)
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001851 WL_ERR("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001852 } else {
1853 if (key.len > sizeof(key.data)) {
1854 WL_ERR("Invalid key length (%d)\n", key.len);
1855 return -EINVAL;
1856 }
1857
1858 WL_CONN("Setting the key index %d\n", key.index);
1859 memcpy(key.data, params->key, key.len);
1860
1861 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1862 u8 keybuf[8];
1863 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1864 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1865 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1866 }
1867
1868 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1869 if (params->seq && params->seq_len == 6) {
1870 /* rx iv */
1871 u8 *ivptr;
1872 ivptr = (u8 *) params->seq;
1873 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1874 (ivptr[3] << 8) | ivptr[2];
1875 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1876 key.iv_initialized = true;
1877 }
1878
1879 switch (params->cipher) {
1880 case WLAN_CIPHER_SUITE_WEP40:
1881 key.algo = CRYPTO_ALGO_WEP1;
1882 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1883 break;
1884 case WLAN_CIPHER_SUITE_WEP104:
1885 key.algo = CRYPTO_ALGO_WEP128;
1886 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1887 break;
1888 case WLAN_CIPHER_SUITE_TKIP:
1889 key.algo = CRYPTO_ALGO_TKIP;
1890 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1891 break;
1892 case WLAN_CIPHER_SUITE_AES_CMAC:
1893 key.algo = CRYPTO_ALGO_AES_CCM;
1894 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1895 break;
1896 case WLAN_CIPHER_SUITE_CCMP:
1897 key.algo = CRYPTO_ALGO_AES_CCM;
1898 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
1899 break;
1900 default:
1901 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1902 return -EINVAL;
1903 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001904 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001905 if (err)
1906 WL_ERR("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001907 }
1908 return err;
1909}
1910
1911static s32
1912brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1913 u8 key_idx, bool pairwise, const u8 *mac_addr,
1914 struct key_params *params)
1915{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001916 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001917 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001918 struct brcmf_wsec_key key;
1919 s32 val;
1920 s32 wsec;
1921 s32 err = 0;
1922 u8 keybuf[8];
1923
1924 WL_TRACE("Enter\n");
1925 WL_CONN("key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001926 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001927 return -EIO;
1928
1929 if (mac_addr) {
1930 WL_TRACE("Exit");
1931 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1932 }
1933 memset(&key, 0, sizeof(key));
1934
1935 key.len = (u32) params->key_len;
1936 key.index = (u32) key_idx;
1937
1938 if (key.len > sizeof(key.data)) {
1939 WL_ERR("Too long key length (%u)\n", key.len);
1940 err = -EINVAL;
1941 goto done;
1942 }
1943 memcpy(key.data, params->key, key.len);
1944
1945 key.flags = BRCMF_PRIMARY_KEY;
1946 switch (params->cipher) {
1947 case WLAN_CIPHER_SUITE_WEP40:
1948 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001949 val = WEP_ENABLED;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001950 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1951 break;
1952 case WLAN_CIPHER_SUITE_WEP104:
1953 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001954 val = WEP_ENABLED;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001955 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1956 break;
1957 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001958 if (cfg->conf->mode != WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001959 WL_CONN("Swapping key\n");
1960 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1961 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1962 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1963 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001964 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001965 val = TKIP_ENABLED;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001966 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1967 break;
1968 case WLAN_CIPHER_SUITE_AES_CMAC:
1969 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001970 val = AES_ENABLED;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001971 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1972 break;
1973 case WLAN_CIPHER_SUITE_CCMP:
1974 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001975 val = AES_ENABLED;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001976 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
1977 break;
1978 default:
1979 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1980 err = -EINVAL;
1981 goto done;
1982 }
1983
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001984 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001985 if (err)
1986 goto done;
1987
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001988 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001989 if (err) {
1990 WL_ERR("get wsec error (%d)\n", err);
1991 goto done;
1992 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001993 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001994 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001995 if (err) {
1996 WL_ERR("set wsec error (%d)\n", err);
1997 goto done;
1998 }
1999
Arend van Spriel5b435de2011-10-05 13:19:03 +02002000done:
2001 WL_TRACE("Exit\n");
2002 return err;
2003}
2004
2005static s32
2006brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
2007 u8 key_idx, bool pairwise, const u8 *mac_addr)
2008{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002009 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002010 struct brcmf_wsec_key key;
2011 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002012
2013 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002014 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002015 return -EIO;
2016
2017 memset(&key, 0, sizeof(key));
2018
2019 key.index = (u32) key_idx;
2020 key.flags = BRCMF_PRIMARY_KEY;
2021 key.algo = CRYPTO_ALGO_OFF;
2022
2023 WL_CONN("key index (%d)\n", key_idx);
2024
2025 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07002026 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002027 if (err) {
2028 if (err == -EINVAL) {
2029 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2030 /* we ignore this key index in this case */
2031 WL_ERR("invalid key index (%d)\n", key_idx);
2032 }
2033 /* Ignore this error, may happen during DISASSOC */
2034 err = -EAGAIN;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002035 }
2036
Arend van Spriel5b435de2011-10-05 13:19:03 +02002037 WL_TRACE("Exit\n");
2038 return err;
2039}
2040
2041static s32
2042brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
2043 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2044 void (*callback) (void *cookie, struct key_params * params))
2045{
2046 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002047 struct brcmf_if *ifp = netdev_priv(ndev);
2048 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002049 struct brcmf_cfg80211_security *sec;
2050 s32 wsec;
2051 s32 err = 0;
2052
2053 WL_TRACE("Enter\n");
2054 WL_CONN("key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07002055 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002056 return -EIO;
2057
2058 memset(&params, 0, sizeof(params));
2059
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002060 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002061 if (err) {
2062 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
2063 /* Ignore this error, may happen during DISASSOC */
2064 err = -EAGAIN;
2065 goto done;
2066 }
Hante Meulemanf09d0c02012-09-27 14:17:48 +02002067 switch (wsec & ~SES_OW_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002068 case WEP_ENABLED:
Arend van Spriel06bb1232012-09-27 14:17:56 +02002069 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002070 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2071 params.cipher = WLAN_CIPHER_SUITE_WEP40;
2072 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
2073 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2074 params.cipher = WLAN_CIPHER_SUITE_WEP104;
2075 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
2076 }
2077 break;
2078 case TKIP_ENABLED:
2079 params.cipher = WLAN_CIPHER_SUITE_TKIP;
2080 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
2081 break;
2082 case AES_ENABLED:
2083 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
2084 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
2085 break;
2086 default:
2087 WL_ERR("Invalid algo (0x%x)\n", wsec);
2088 err = -EINVAL;
2089 goto done;
2090 }
2091 callback(cookie, &params);
2092
2093done:
2094 WL_TRACE("Exit\n");
2095 return err;
2096}
2097
2098static s32
2099brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2100 struct net_device *ndev, u8 key_idx)
2101{
2102 WL_INFO("Not supported\n");
2103
2104 return -EOPNOTSUPP;
2105}
2106
2107static s32
2108brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02002109 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002110{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002111 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002112 struct brcmf_if *ifp = netdev_priv(ndev);
2113 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002114 struct brcmf_scb_val_le scb_val;
2115 int rssi;
2116 s32 rate;
2117 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02002118 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002119 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120
Hante Meuleman1a873342012-09-27 14:17:54 +02002121 WL_TRACE("Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07002122 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002123 return -EIO;
2124
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002125 if (cfg->conf->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002126 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002127 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07002128 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002129 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02002130 if (err < 0) {
2131 WL_ERR("GET STA INFO failed, %d\n", err);
2132 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02002133 }
Hante Meuleman1a873342012-09-27 14:17:54 +02002134 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002135 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
2136 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002137 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002138 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02002139 }
2140 WL_TRACE("STA idle time : %d ms, connected time :%d sec\n",
2141 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002142 } else if (cfg->conf->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002143 if (memcmp(mac, bssid, ETH_ALEN)) {
2144 WL_ERR("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
2145 mac, bssid);
2146 err = -ENOENT;
2147 goto done;
2148 }
2149 /* Report the current tx rate */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002150 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02002151 if (err) {
2152 WL_ERR("Could not get rate (%d)\n", err);
2153 goto done;
2154 } else {
2155 sinfo->filled |= STATION_INFO_TX_BITRATE;
2156 sinfo->txrate.legacy = rate * 5;
2157 WL_CONN("Rate %d Mbps\n", rate / 2);
2158 }
2159
Arend van Sprielc1179032012-10-22 13:55:33 -07002160 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
2161 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002162 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07002163 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
2164 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02002165 if (err) {
2166 WL_ERR("Could not get rssi (%d)\n", err);
2167 goto done;
2168 } else {
2169 rssi = le32_to_cpu(scb_val.val);
2170 sinfo->filled |= STATION_INFO_SIGNAL;
2171 sinfo->signal = rssi;
2172 WL_CONN("RSSI %d dBm\n", rssi);
2173 }
2174 }
2175 } else
2176 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002177done:
2178 WL_TRACE("Exit\n");
2179 return err;
2180}
2181
2182static s32
2183brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
2184 bool enabled, s32 timeout)
2185{
2186 s32 pm;
2187 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002188 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002189 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002190
2191 WL_TRACE("Enter\n");
2192
2193 /*
2194 * Powersave enable/disable request is coming from the
2195 * cfg80211 even before the interface is up. In that
2196 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002197 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02002198 * FW later while initializing the dongle
2199 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002200 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07002201 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002202
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002203 WL_INFO("Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002204 goto done;
2205 }
2206
2207 pm = enabled ? PM_FAST : PM_OFF;
2208 WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
2209
Arend van Sprielc1179032012-10-22 13:55:33 -07002210 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002211 if (err) {
2212 if (err == -ENODEV)
2213 WL_ERR("net_device is not ready yet\n");
2214 else
2215 WL_ERR("error (%d)\n", err);
2216 }
2217done:
2218 WL_TRACE("Exit\n");
2219 return err;
2220}
2221
2222static s32
2223brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
2224 const u8 *addr,
2225 const struct cfg80211_bitrate_mask *mask)
2226{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002227 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002228 struct brcm_rateset_le rateset_le;
2229 s32 rate;
2230 s32 val;
2231 s32 err_bg;
2232 s32 err_a;
2233 u32 legacy;
2234 s32 err = 0;
2235
2236 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002237 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238 return -EIO;
2239
2240 /* addr param is always NULL. ignore it */
2241 /* Get current rateset */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002242 err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET,
Arend van Sprielac24be62012-10-22 10:36:23 -07002243 &rateset_le, sizeof(rateset_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002244 if (err) {
2245 WL_ERR("could not get current rateset (%d)\n", err);
2246 goto done;
2247 }
2248
2249 legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
2250 if (!legacy)
2251 legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
2252 0xFFFF);
2253
2254 val = wl_g_rates[legacy - 1].bitrate * 100000;
2255
2256 if (val < le32_to_cpu(rateset_le.count))
2257 /* Select rate by rateset index */
2258 rate = rateset_le.rates[val] & 0x7f;
2259 else
2260 /* Specified rate in bps */
2261 rate = val / 500000;
2262
2263 WL_CONN("rate %d mbps\n", rate / 2);
2264
2265 /*
2266 *
2267 * Set rate override,
2268 * Since the is a/b/g-blind, both a/bg_rate are enforced.
2269 */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002270 err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
2271 err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002272 if (err_bg && err_a) {
2273 WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
2274 err = err_bg | err_a;
2275 }
2276
2277done:
2278 WL_TRACE("Exit\n");
2279 return err;
2280}
2281
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002282static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002283 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002284{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002285 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002286 struct ieee80211_channel *notify_channel;
2287 struct cfg80211_bss *bss;
2288 struct ieee80211_supported_band *band;
2289 s32 err = 0;
2290 u16 channel;
2291 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002292 u16 notify_capability;
2293 u16 notify_interval;
2294 u8 *notify_ie;
2295 size_t notify_ielen;
2296 s32 notify_signal;
2297
2298 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
2299 WL_ERR("Bss info is larger than buffer. Discarding\n");
2300 return 0;
2301 }
2302
2303 channel = bi->ctl_ch ? bi->ctl_ch :
2304 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2305
2306 if (channel <= CH_MAX_2G_CHANNEL)
2307 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2308 else
2309 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2310
2311 freq = ieee80211_channel_to_frequency(channel, band->band);
2312 notify_channel = ieee80211_get_channel(wiphy, freq);
2313
Arend van Spriel5b435de2011-10-05 13:19:03 +02002314 notify_capability = le16_to_cpu(bi->capability);
2315 notify_interval = le16_to_cpu(bi->beacon_period);
2316 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2317 notify_ielen = le32_to_cpu(bi->ie_length);
2318 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2319
2320 WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
2321 bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
2322 bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
2323 WL_CONN("Channel: %d(%d)\n", channel, freq);
2324 WL_CONN("Capability: %X\n", notify_capability);
2325 WL_CONN("Beacon interval: %d\n", notify_interval);
2326 WL_CONN("Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002327
2328 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002329 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002330 notify_ielen, notify_signal, GFP_KERNEL);
2331
Franky Line78946e2011-11-10 20:30:34 +01002332 if (!bss)
2333 return -ENOMEM;
2334
2335 cfg80211_put_bss(bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336
2337 return err;
2338}
2339
Roland Vossen6f09be02011-10-18 14:03:02 +02002340static struct brcmf_bss_info_le *
2341next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2342{
2343 if (bss == NULL)
2344 return list->bss_info_le;
2345 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2346 le32_to_cpu(bss->length));
2347}
2348
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002349static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002350{
2351 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002352 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002353 s32 err = 0;
2354 int i;
2355
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002356 bss_list = cfg->bss_list;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002357 if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
2358 WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
2359 bss_list->version);
2360 return -EOPNOTSUPP;
2361 }
2362 WL_SCAN("scanned AP count (%d)\n", bss_list->count);
2363 for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002364 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002365 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002366 if (err)
2367 break;
2368 }
2369 return err;
2370}
2371
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002372static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002373 struct net_device *ndev, const u8 *bssid)
2374{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002375 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002376 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002377 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002378 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002379 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002380 u8 *buf = NULL;
2381 s32 err = 0;
2382 u16 channel;
2383 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002384 u16 notify_capability;
2385 u16 notify_interval;
2386 u8 *notify_ie;
2387 size_t notify_ielen;
2388 s32 notify_signal;
2389
2390 WL_TRACE("Enter\n");
2391
2392 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2393 if (buf == NULL) {
2394 err = -ENOMEM;
2395 goto CleanUp;
2396 }
2397
2398 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2399
Arend van Sprielac24be62012-10-22 10:36:23 -07002400 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2401 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002402 if (err) {
2403 WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
2404 goto CleanUp;
2405 }
2406
Roland Vossend34bf642011-10-18 14:03:01 +02002407 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002408
2409 channel = bi->ctl_ch ? bi->ctl_ch :
2410 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2411
2412 if (channel <= CH_MAX_2G_CHANNEL)
2413 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2414 else
2415 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2416
2417 freq = ieee80211_channel_to_frequency(channel, band->band);
2418 notify_channel = ieee80211_get_channel(wiphy, freq);
2419
Arend van Spriel5b435de2011-10-05 13:19:03 +02002420 notify_capability = le16_to_cpu(bi->capability);
2421 notify_interval = le16_to_cpu(bi->beacon_period);
2422 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2423 notify_ielen = le32_to_cpu(bi->ie_length);
2424 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2425
2426 WL_CONN("channel: %d(%d)\n", channel, freq);
2427 WL_CONN("capability: %X\n", notify_capability);
2428 WL_CONN("beacon interval: %d\n", notify_interval);
2429 WL_CONN("signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002430
Franky Line78946e2011-11-10 20:30:34 +01002431 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002432 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002433 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2434
Franky Line78946e2011-11-10 20:30:34 +01002435 if (!bss) {
2436 err = -ENOMEM;
2437 goto CleanUp;
2438 }
2439
2440 cfg80211_put_bss(bss);
2441
Arend van Spriel5b435de2011-10-05 13:19:03 +02002442CleanUp:
2443
2444 kfree(buf);
2445
2446 WL_TRACE("Exit\n");
2447
2448 return err;
2449}
2450
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002451static bool brcmf_is_ibssmode(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002452{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002453 return cfg->conf->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002454}
2455
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002456/*
2457 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2458 * triples, returning a pointer to the substring whose first element
2459 * matches tag
2460 */
2461static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
2462{
2463 struct brcmf_tlv *elt;
2464 int totlen;
2465
2466 elt = (struct brcmf_tlv *) buf;
2467 totlen = buflen;
2468
2469 /* find tagged parameter */
Hante Meuleman04012892012-09-27 14:17:49 +02002470 while (totlen >= TLV_HDR_LEN) {
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002471 int len = elt->len;
2472
2473 /* validate remaining totlen */
Hante Meuleman04012892012-09-27 14:17:49 +02002474 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002475 return elt;
2476
Hante Meuleman04012892012-09-27 14:17:49 +02002477 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
2478 totlen -= (len + TLV_HDR_LEN);
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002479 }
2480
2481 return NULL;
2482}
2483
Hante Meuleman1a873342012-09-27 14:17:54 +02002484/* Is any of the tlvs the expected entry? If
2485 * not update the tlvs buffer pointer/length.
2486 */
2487static bool
2488brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
2489 u8 *oui, u32 oui_len, u8 type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002490{
Hante Meuleman1a873342012-09-27 14:17:54 +02002491 /* If the contents match the OUI and the type */
2492 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
2493 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
2494 type == ie[TLV_BODY_OFF + oui_len]) {
2495 return true;
2496 }
2497
2498 if (tlvs == NULL)
2499 return false;
2500 /* point to the next ie */
2501 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
2502 /* calculate the length of the rest of the buffer */
2503 *tlvs_len -= (int)(ie - *tlvs);
2504 /* update the pointer to the start of the buffer */
2505 *tlvs = ie;
2506
2507 return false;
2508}
2509
Franky Lin3cb91f52012-10-10 11:13:08 -07002510static struct brcmf_vs_tlv *
Hante Meuleman1a873342012-09-27 14:17:54 +02002511brcmf_find_wpaie(u8 *parse, u32 len)
2512{
2513 struct brcmf_tlv *ie;
2514
Arend van Spriel04b23122012-10-12 12:28:14 +02002515 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002516 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
2517 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
2518 return (struct brcmf_vs_tlv *)ie;
2519 }
2520 return NULL;
2521}
2522
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002523static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002524{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07002525 struct net_device *ndev = cfg_to_ndev(cfg);
2526 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
2527 struct brcmf_if *ifp = netdev_priv(ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002528 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002529 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002530 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002531 u16 beacon_interval;
2532 u8 dtim_period;
2533 size_t ie_len;
2534 u8 *ie;
2535 s32 err = 0;
2536
2537 WL_TRACE("Enter\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002538 if (brcmf_is_ibssmode(cfg))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002539 return err;
2540
Arend van Spriel06bb1232012-09-27 14:17:56 +02002541 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002542
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002543 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002544 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002545 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002546 if (err) {
2547 WL_ERR("Could not get bss info %d\n", err);
2548 goto update_bss_info_out;
2549 }
2550
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002551 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2552 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002553 if (err)
2554 goto update_bss_info_out;
2555
2556 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2557 ie_len = le32_to_cpu(bi->ie_length);
2558 beacon_interval = le16_to_cpu(bi->beacon_period);
2559
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002560 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002561 if (tim)
2562 dtim_period = tim->data[1];
2563 else {
2564 /*
2565 * active scan was done so we could not get dtim
2566 * information out of probe response.
2567 * so we speficially query dtim information to dongle.
2568 */
2569 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002570 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002571 if (err) {
2572 WL_ERR("wl dtim_assoc failed (%d)\n", err);
2573 goto update_bss_info_out;
2574 }
2575 dtim_period = (u8)var;
2576 }
2577
Arend van Spriel5b435de2011-10-05 13:19:03 +02002578update_bss_info_out:
2579 WL_TRACE("Exit");
2580 return err;
2581}
2582
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002583static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002584{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002585 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
2586 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002587 struct brcmf_ssid ssid;
2588
Arend van Sprielc1179032012-10-22 13:55:33 -07002589 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002590 if (cfg->iscan_on) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002591 iscan->state = WL_ISCAN_STATE_IDLE;
2592
2593 if (iscan->timer_on) {
2594 del_timer_sync(&iscan->timer);
2595 iscan->timer_on = 0;
2596 }
2597
2598 cancel_work_sync(&iscan->work);
2599
2600 /* Abort iscan running in FW */
2601 memset(&ssid, 0, sizeof(ssid));
2602 brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002603
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002604 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002605 /* Indidate scan abort to cfg80211 layer */
2606 WL_INFO("Terminating scan in progress\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002607 cfg80211_scan_done(cfg->scan_request, true);
2608 cfg->scan_request = NULL;
Arend van Spriel108a4be2012-09-19 22:21:07 +02002609 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002610 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002611 if (cfg->escan_on && cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002612 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002613 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002614 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002615 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2616 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002617}
2618
2619static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
2620 bool aborted)
2621{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002622 struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
2623 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002624
Arend van Sprielc1179032012-10-22 13:55:33 -07002625 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002626 WL_ERR("Scan complete while device not scanning\n");
2627 return;
2628 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002629 if (cfg->scan_request) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002630 WL_SCAN("ISCAN Completed scan: %s\n",
2631 aborted ? "Aborted" : "Done");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002632 cfg80211_scan_done(cfg->scan_request, aborted);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002633 brcmf_set_mpc(ndev, 1);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002634 cfg->scan_request = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002635 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002636 cfg->iscan_kickstart = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002637}
2638
2639static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
2640{
2641 if (iscan->state != WL_ISCAN_STATE_IDLE) {
2642 WL_SCAN("wake up iscan\n");
2643 schedule_work(&iscan->work);
2644 return 0;
2645 }
2646
2647 return -EIO;
2648}
2649
2650static s32
2651brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
2652 struct brcmf_scan_results **bss_list)
2653{
Arend van Spriel5b435de2011-10-05 13:19:03 +02002654 struct brcmf_scan_results *results;
2655 struct brcmf_scan_results_le *results_le;
2656 struct brcmf_iscan_results *list_buf;
2657 s32 err = 0;
2658
2659 memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
2660 list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
2661 results = &list_buf->results;
2662 results_le = &list_buf->results_le;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002663 results_le->buflen = cpu_to_le32(sizeof(iscan->scan_buf));
2664 results_le->version = 0;
2665 results_le->count = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002666
Arend van Sprielac24be62012-10-22 10:36:23 -07002667 err = brcmf_fil_iovar_data_get(netdev_priv(iscan->ndev), "iscanresults",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002668 iscan->scan_buf,
2669 sizeof(iscan->scan_buf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002670 if (err) {
2671 WL_ERR("error (%d)\n", err);
2672 return err;
2673 }
2674 results->buflen = le32_to_cpu(results_le->buflen);
2675 results->version = le32_to_cpu(results_le->version);
2676 results->count = le32_to_cpu(results_le->count);
2677 WL_SCAN("results->count = %d\n", results_le->count);
2678 WL_SCAN("results->buflen = %d\n", results_le->buflen);
2679 *status = le32_to_cpu(list_buf->status_le);
2680 WL_SCAN("status = %d\n", *status);
2681 *bss_list = results;
2682
2683 return err;
2684}
2685
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002686static s32 brcmf_iscan_done(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002687{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002688 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002689 s32 err = 0;
2690
2691 iscan->state = WL_ISCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002692 brcmf_inform_bss(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002693 brcmf_notify_iscan_complete(iscan, false);
2694
2695 return err;
2696}
2697
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002698static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002699{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002700 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002701 s32 err = 0;
2702
2703 /* Reschedule the timer */
2704 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
2705 iscan->timer_on = 1;
2706
2707 return err;
2708}
2709
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002710static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002711{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002712 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002713 s32 err = 0;
2714
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002715 brcmf_inform_bss(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002716 brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
2717 /* Reschedule the timer */
2718 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
2719 iscan->timer_on = 1;
2720
2721 return err;
2722}
2723
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002724static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002725{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002726 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002727 s32 err = 0;
2728
2729 iscan->state = WL_ISCAN_STATE_IDLE;
2730 brcmf_notify_iscan_complete(iscan, true);
2731
2732 return err;
2733}
2734
2735static void brcmf_cfg80211_iscan_handler(struct work_struct *work)
2736{
2737 struct brcmf_cfg80211_iscan_ctrl *iscan =
2738 container_of(work, struct brcmf_cfg80211_iscan_ctrl,
2739 work);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002740 struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002741 struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
2742 u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
2743
2744 if (iscan->timer_on) {
2745 del_timer_sync(&iscan->timer);
2746 iscan->timer_on = 0;
2747 }
2748
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002749 if (brcmf_get_iscan_results(iscan, &status, &cfg->bss_list)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002750 status = BRCMF_SCAN_RESULTS_ABORTED;
2751 WL_ERR("Abort iscan\n");
2752 }
2753
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002754 el->handler[status](cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002755}
2756
2757static void brcmf_iscan_timer(unsigned long data)
2758{
2759 struct brcmf_cfg80211_iscan_ctrl *iscan =
2760 (struct brcmf_cfg80211_iscan_ctrl *)data;
2761
2762 if (iscan) {
2763 iscan->timer_on = 0;
2764 WL_SCAN("timer expired\n");
2765 brcmf_wakeup_iscan(iscan);
2766 }
2767}
2768
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002769static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002770{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002771 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002772
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002773 if (cfg->iscan_on) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002774 iscan->state = WL_ISCAN_STATE_IDLE;
2775 INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
2776 }
2777
2778 return 0;
2779}
2780
2781static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
2782{
2783 memset(el, 0, sizeof(*el));
2784 el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
2785 el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
2786 el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
2787 el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
2788 el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
2789}
2790
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002791static s32 brcmf_init_iscan(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002792{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002793 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002794 int err = 0;
2795
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002796 if (cfg->iscan_on) {
2797 iscan->ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002798 brcmf_init_iscan_eloop(&iscan->el);
2799 iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
2800 init_timer(&iscan->timer);
2801 iscan->timer.data = (unsigned long) iscan;
2802 iscan->timer.function = brcmf_iscan_timer;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002803 err = brcmf_invoke_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002804 if (!err)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002805 iscan->data = cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002806 }
2807
2808 return err;
2809}
2810
Hante Meulemane756af52012-09-11 21:18:52 +02002811static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2812{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002813 struct brcmf_cfg80211_info *cfg =
2814 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002815 escan_timeout_work);
2816
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002817 brcmf_notify_escan_complete(cfg,
2818 cfg->escan_info.ndev, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002819}
2820
2821static void brcmf_escan_timeout(unsigned long data)
2822{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002823 struct brcmf_cfg80211_info *cfg =
2824 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002825
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002826 if (cfg->scan_request) {
Hante Meulemane756af52012-09-11 21:18:52 +02002827 WL_ERR("timer expired\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002828 if (cfg->escan_on)
2829 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002830 }
2831}
2832
2833static s32
2834brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2835 struct brcmf_bss_info_le *bss_info_le)
2836{
2837 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2838 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2839 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2840 bss_info_le->SSID_len == bss->SSID_len &&
2841 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2842 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2843 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002844 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2845 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2846
Hante Meulemane756af52012-09-11 21:18:52 +02002847 /* preserve max RSSI if the measurements are
2848 * both on-channel or both off-channel
2849 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002850 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002851 bss->RSSI = bss_info_le->RSSI;
2852 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2853 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2854 /* preserve the on-channel rssi measurement
2855 * if the new measurement is off channel
2856 */
2857 bss->RSSI = bss_info_le->RSSI;
2858 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2859 }
2860 return 1;
2861 }
2862 return 0;
2863}
2864
2865static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002866brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg,
Hante Meulemane756af52012-09-11 21:18:52 +02002867 struct net_device *ndev,
2868 const struct brcmf_event_msg *e, void *data)
2869{
2870 s32 status;
2871 s32 err = 0;
2872 struct brcmf_escan_result_le *escan_result_le;
2873 struct brcmf_bss_info_le *bss_info_le;
2874 struct brcmf_bss_info_le *bss = NULL;
2875 u32 bi_length;
2876 struct brcmf_scan_results *list;
2877 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002878 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002879
2880 status = be32_to_cpu(e->status);
2881
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002882 if (!ndev || !cfg->escan_on ||
Arend van Sprielc1179032012-10-22 13:55:33 -07002883 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Hante Meulemane756af52012-09-11 21:18:52 +02002884 WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n",
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002885 ndev, cfg->escan_on,
Arend van Sprielc1179032012-10-22 13:55:33 -07002886 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
Hante Meulemane756af52012-09-11 21:18:52 +02002887 return -EPERM;
2888 }
2889
2890 if (status == BRCMF_E_STATUS_PARTIAL) {
2891 WL_SCAN("ESCAN Partial result\n");
2892 escan_result_le = (struct brcmf_escan_result_le *) data;
2893 if (!escan_result_le) {
2894 WL_ERR("Invalid escan result (NULL pointer)\n");
2895 goto exit;
2896 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002897 if (!cfg->scan_request) {
Hante Meulemane756af52012-09-11 21:18:52 +02002898 WL_SCAN("result without cfg80211 request\n");
2899 goto exit;
2900 }
2901
2902 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
2903 WL_ERR("Invalid bss_count %d: ignoring\n",
2904 escan_result_le->bss_count);
2905 goto exit;
2906 }
2907 bss_info_le = &escan_result_le->bss_info_le;
2908
2909 bi_length = le32_to_cpu(bss_info_le->length);
2910 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2911 WL_ESCAN_RESULTS_FIXED_SIZE)) {
2912 WL_ERR("Invalid bss_info length %d: ignoring\n",
2913 bi_length);
2914 goto exit;
2915 }
2916
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002917 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002918 BIT(NL80211_IFTYPE_ADHOC))) {
2919 if (le16_to_cpu(bss_info_le->capability) &
2920 WLAN_CAPABILITY_IBSS) {
2921 WL_ERR("Ignoring IBSS result\n");
2922 goto exit;
2923 }
2924 }
2925
2926 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002927 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002928 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
2929 WL_ERR("Buffer is too small: ignoring\n");
2930 goto exit;
2931 }
2932
2933 for (i = 0; i < list->count; i++) {
2934 bss = bss ? (struct brcmf_bss_info_le *)
2935 ((unsigned char *)bss +
2936 le32_to_cpu(bss->length)) : list->bss_info_le;
2937 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2938 goto exit;
2939 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002940 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002941 bss_info_le, bi_length);
2942 list->version = le32_to_cpu(bss_info_le->version);
2943 list->buflen += bi_length;
2944 list->count++;
2945 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002946 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2947 if (cfg->scan_request) {
2948 cfg->bss_list = (struct brcmf_scan_results *)
2949 cfg->escan_info.escan_buf;
2950 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002951 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002952 brcmf_notify_escan_complete(cfg, ndev, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002953 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002954 } else
2955 WL_ERR("Unexpected scan result 0x%x\n", status);
2956 }
2957exit:
2958 return err;
2959}
2960
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002961static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002962{
2963
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002964 if (cfg->escan_on) {
2965 cfg->el.handler[BRCMF_E_ESCAN_RESULT] =
Hante Meulemane756af52012-09-11 21:18:52 +02002966 brcmf_cfg80211_escan_handler;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002967 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
Hante Meulemane756af52012-09-11 21:18:52 +02002968 /* Init scan_timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002969 init_timer(&cfg->escan_timeout);
2970 cfg->escan_timeout.data = (unsigned long) cfg;
2971 cfg->escan_timeout.function = brcmf_escan_timeout;
2972 INIT_WORK(&cfg->escan_timeout_work,
Hante Meulemane756af52012-09-11 21:18:52 +02002973 brcmf_cfg80211_escan_timeout_worker);
2974 }
2975}
2976
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002977static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002978{
2979 if (ms < 1000 / HZ) {
2980 cond_resched();
2981 mdelay(ms);
2982 } else {
2983 msleep(ms);
2984 }
2985}
2986
2987static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2988{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002989 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07002990 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002991
2992 /*
Arend van Sprielc1179032012-10-22 13:55:33 -07002993 * Check for BRCMF_VIF_STATUS_READY before any function call which
Arend van Spriel5b435de2011-10-05 13:19:03 +02002994 * could result is bus access. Don't block the resume for
2995 * any driver error conditions
2996 */
2997 WL_TRACE("Enter\n");
2998
Arend van Sprielce81e312012-10-22 13:55:37 -07002999 if (check_vif_up(ifp->vif))
Arend van Spriel823e1c82012-10-22 13:55:40 -07003000 brcmf_invoke_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003001
3002 WL_TRACE("Exit\n");
3003 return 0;
3004}
3005
3006static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
3007 struct cfg80211_wowlan *wow)
3008{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003009 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3010 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07003011 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003012
3013 WL_TRACE("Enter\n");
3014
3015 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07003016 * if the primary net_device is not READY there is nothing
3017 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003018 */
Arend van Spriel7d641072012-10-22 13:55:39 -07003019 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
3020 if (!check_vif_up(vif))
3021 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003022
Arend van Spriel7d641072012-10-22 13:55:39 -07003023 list_for_each_entry(vif, &cfg->vif_list, list) {
3024 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
3025 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003026 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07003027 * While going to suspend if associated with AP disassociate
3028 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02003029 */
Arend van Spriel7d641072012-10-22 13:55:39 -07003030 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) ||
3031 test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
3032 WL_INFO("Disassociating from AP before suspend\n");
3033 brcmf_link_down(cfg);
3034
3035 /* Make sure WPA_Supplicant receives all the event
3036 * generated due to DISASSOC call to the fw to keep
3037 * the state fw and WPA_Supplicant state consistent
3038 */
3039 brcmf_delay(500);
3040 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003041 }
3042
Arend van Spriel7d641072012-10-22 13:55:39 -07003043 /* end any scanning */
3044 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003045 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003046
3047 /* Turn off watchdog timer */
Arend van Spriel7d641072012-10-22 13:55:39 -07003048 brcmf_set_mpc(ndev, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003049
Arend van Spriel7d641072012-10-22 13:55:39 -07003050exit:
Arend van Spriel5b435de2011-10-05 13:19:03 +02003051 WL_TRACE("Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07003052 /* clear any scanning activity */
3053 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003054 return 0;
3055}
3056
3057static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02003058brcmf_update_pmklist(struct net_device *ndev,
3059 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
3060{
3061 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02003062 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003063
Arend van Spriel40c8e952011-10-12 20:51:20 +02003064 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
3065
3066 WL_CONN("No of elements %d\n", pmkid_len);
3067 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003068 WL_CONN("PMKID[%d]: %pM =\n", i,
3069 &pmk_list->pmkids.pmkid[i].BSSID);
3070 for (j = 0; j < WLAN_PMKID_LEN; j++)
3071 WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
3072 }
3073
3074 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07003075 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
3076 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003077
3078 return err;
3079}
3080
3081static s32
3082brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3083 struct cfg80211_pmksa *pmksa)
3084{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003085 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003086 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003087 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003088 s32 err = 0;
3089 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02003090 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003091
3092 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003093 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003094 return -EIO;
3095
Arend van Spriel40c8e952011-10-12 20:51:20 +02003096 pmkid_len = le32_to_cpu(pmkids->npmkid);
3097 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003098 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
3099 break;
3100 if (i < WL_NUM_PMKIDS_MAX) {
3101 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
3102 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003103 if (i == pmkid_len) {
3104 pmkid_len++;
3105 pmkids->npmkid = cpu_to_le32(pmkid_len);
3106 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003107 } else
3108 err = -EINVAL;
3109
3110 WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
Arend van Spriel40c8e952011-10-12 20:51:20 +02003111 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003112 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel40c8e952011-10-12 20:51:20 +02003113 WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003114
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003115 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003116
3117 WL_TRACE("Exit\n");
3118 return err;
3119}
3120
3121static s32
3122brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
3123 struct cfg80211_pmksa *pmksa)
3124{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003125 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003126 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003127 struct pmkid_list pmkid;
3128 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02003129 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003130
3131 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003132 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003133 return -EIO;
3134
3135 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
3136 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
3137
3138 WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3139 &pmkid.pmkid[0].BSSID);
3140 for (i = 0; i < WLAN_PMKID_LEN; i++)
3141 WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
3142
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003143 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02003144 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003145 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003146 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003147 ETH_ALEN))
3148 break;
3149
Arend van Spriel40c8e952011-10-12 20:51:20 +02003150 if ((pmkid_len > 0)
3151 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003152 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003153 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02003154 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003155 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
3156 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003157 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003158 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
3159 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003160 WLAN_PMKID_LEN);
3161 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003162 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003163 } else
3164 err = -EINVAL;
3165
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003166 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003167
3168 WL_TRACE("Exit\n");
3169 return err;
3170
3171}
3172
3173static s32
3174brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
3175{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003176 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003177 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003178 s32 err = 0;
3179
3180 WL_TRACE("Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07003181 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02003182 return -EIO;
3183
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003184 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
3185 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003186
3187 WL_TRACE("Exit\n");
3188 return err;
3189
3190}
3191
Arend van Spriele5806072012-09-19 22:21:08 +02003192/*
3193 * PFN result doesn't have all the info which are
3194 * required by the supplicant
3195 * (For e.g IEs) Do a target Escan so that sched scan results are reported
3196 * via wl_inform_single_bss in the required format. Escan does require the
3197 * scan request in the form of cfg80211_scan_request. For timebeing, create
3198 * cfg80211_scan_request one out of the received PNO event.
3199 */
3200static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003201brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,
Arend van Spriele5806072012-09-19 22:21:08 +02003202 struct net_device *ndev,
3203 const struct brcmf_event_msg *e, void *data)
3204{
3205 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
3206 struct cfg80211_scan_request *request = NULL;
3207 struct cfg80211_ssid *ssid = NULL;
3208 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003209 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02003210 int err = 0;
3211 int channel_req = 0;
3212 int band = 0;
3213 struct brcmf_pno_scanresults_le *pfn_result;
3214 u32 result_count;
3215 u32 status;
3216
3217 WL_SCAN("Enter\n");
3218
3219 if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) {
3220 WL_SCAN("PFN NET LOST event. Do Nothing\n");
3221 return 0;
3222 }
3223
3224 pfn_result = (struct brcmf_pno_scanresults_le *)data;
3225 result_count = le32_to_cpu(pfn_result->count);
3226 status = le32_to_cpu(pfn_result->status);
3227
3228 /*
3229 * PFN event is limited to fit 512 bytes so we may get
3230 * multiple NET_FOUND events. For now place a warning here.
3231 */
3232 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3233 WL_SCAN("PFN NET FOUND event. count: %d\n", result_count);
3234 if (result_count > 0) {
3235 int i;
3236
3237 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03003238 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
3239 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02003240 if (!request || !ssid || !channel) {
3241 err = -ENOMEM;
3242 goto out_err;
3243 }
3244
3245 request->wiphy = wiphy;
3246 data += sizeof(struct brcmf_pno_scanresults_le);
3247 netinfo_start = (struct brcmf_pno_net_info_le *)data;
3248
3249 for (i = 0; i < result_count; i++) {
3250 netinfo = &netinfo_start[i];
3251 if (!netinfo) {
3252 WL_ERR("Invalid netinfo ptr. index: %d\n", i);
3253 err = -EINVAL;
3254 goto out_err;
3255 }
3256
3257 WL_SCAN("SSID:%s Channel:%d\n",
3258 netinfo->SSID, netinfo->channel);
3259 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
3260 ssid[i].ssid_len = netinfo->SSID_len;
3261 request->n_ssids++;
3262
3263 channel_req = netinfo->channel;
3264 if (channel_req <= CH_MAX_2G_CHANNEL)
3265 band = NL80211_BAND_2GHZ;
3266 else
3267 band = NL80211_BAND_5GHZ;
3268 channel[i].center_freq =
3269 ieee80211_channel_to_frequency(channel_req,
3270 band);
3271 channel[i].band = band;
3272 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
3273 request->channels[i] = &channel[i];
3274 request->n_channels++;
3275 }
3276
3277 /* assign parsed ssid array */
3278 if (request->n_ssids)
3279 request->ssids = &ssid[0];
3280
Arend van Sprielc1179032012-10-22 13:55:33 -07003281 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02003282 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003283 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02003284 }
3285
Arend van Sprielc1179032012-10-22 13:55:33 -07003286 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003287 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriele5806072012-09-19 22:21:08 +02003288 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003289 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003290 goto out_err;
3291 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003292 cfg->sched_escan = true;
3293 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02003294 } else {
3295 WL_ERR("FALSE PNO Event. (pfn_count == 0)\n");
3296 goto out_err;
3297 }
3298
3299 kfree(ssid);
3300 kfree(channel);
3301 kfree(request);
3302 return 0;
3303
3304out_err:
3305 kfree(ssid);
3306 kfree(channel);
3307 kfree(request);
3308 cfg80211_sched_scan_stopped(wiphy);
3309 return err;
3310}
3311
3312#ifndef CONFIG_BRCMISCAN
3313static int brcmf_dev_pno_clean(struct net_device *ndev)
3314{
Arend van Spriele5806072012-09-19 22:21:08 +02003315 int ret;
3316
3317 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003318 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003319 if (ret == 0) {
3320 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07003321 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
3322 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02003323 }
3324 if (ret < 0)
3325 WL_ERR("failed code %d\n", ret);
3326
3327 return ret;
3328}
3329
3330static int brcmf_dev_pno_config(struct net_device *ndev)
3331{
3332 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02003333
3334 memset(&pfn_param, 0, sizeof(pfn_param));
3335 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
3336
3337 /* set extra pno params */
3338 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
3339 pfn_param.repeat = BRCMF_PNO_REPEAT;
3340 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
3341
3342 /* set up pno scan fr */
3343 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
3344
Arend van Sprielac24be62012-10-22 10:36:23 -07003345 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
3346 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02003347}
3348
3349static int
3350brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
3351 struct net_device *ndev,
3352 struct cfg80211_sched_scan_request *request)
3353{
Arend van Sprielc1179032012-10-22 13:55:33 -07003354 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003355 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003356 struct brcmf_pno_net_param_le pfn;
3357 int i;
3358 int ret = 0;
3359
3360 WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n",
3361 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07003362 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3363 WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02003364 return -EAGAIN;
3365 }
3366
3367 if (!request || !request->n_ssids || !request->n_match_sets) {
3368 WL_ERR("Invalid sched scan req!! n_ssids:%d\n",
3369 request->n_ssids);
3370 return -EINVAL;
3371 }
3372
3373 if (request->n_ssids > 0) {
3374 for (i = 0; i < request->n_ssids; i++) {
3375 /* Active scan req for ssids */
3376 WL_SCAN(">>> Active scan req for ssid (%s)\n",
3377 request->ssids[i].ssid);
3378
3379 /*
3380 * match_set ssids is a supert set of n_ssid list,
3381 * so we need not add these set seperately.
3382 */
3383 }
3384 }
3385
3386 if (request->n_match_sets > 0) {
3387 /* clean up everything */
3388 ret = brcmf_dev_pno_clean(ndev);
3389 if (ret < 0) {
3390 WL_ERR("failed error=%d\n", ret);
3391 return ret;
3392 }
3393
3394 /* configure pno */
3395 ret = brcmf_dev_pno_config(ndev);
3396 if (ret < 0) {
3397 WL_ERR("PNO setup failed!! ret=%d\n", ret);
3398 return -EINVAL;
3399 }
3400
3401 /* configure each match set */
3402 for (i = 0; i < request->n_match_sets; i++) {
3403 struct cfg80211_ssid *ssid;
3404 u32 ssid_len;
3405
3406 ssid = &request->match_sets[i].ssid;
3407 ssid_len = ssid->ssid_len;
3408
3409 if (!ssid_len) {
3410 WL_ERR("skip broadcast ssid\n");
3411 continue;
3412 }
3413 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
3414 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
3415 pfn.wsec = cpu_to_le32(0);
3416 pfn.infra = cpu_to_le32(1);
3417 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
3418 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
3419 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07003420 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07003421 sizeof(pfn));
Arend van Spriele5806072012-09-19 22:21:08 +02003422 WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
3423 ret == 0 ? "set" : "failed",
3424 ssid->ssid);
3425 }
3426 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07003427 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriele5806072012-09-19 22:21:08 +02003428 WL_ERR("PNO enable failed!! ret=%d\n", ret);
3429 return -EINVAL;
3430 }
3431 } else {
3432 return -EINVAL;
3433 }
3434
3435 return 0;
3436}
3437
3438static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
3439 struct net_device *ndev)
3440{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003441 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02003442
3443 WL_SCAN("enter\n");
3444 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003445 if (cfg->sched_escan)
3446 brcmf_notify_escan_complete(cfg, ndev, true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02003447 return 0;
3448}
3449#endif /* CONFIG_BRCMISCAN */
3450
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003451#ifdef CONFIG_NL80211_TESTMODE
3452static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
3453{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003454 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003455 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003456 struct brcmf_dcmd *dcmd = data;
3457 struct sk_buff *reply;
3458 int ret;
3459
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003460 WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
3461 dcmd->buf, dcmd->len);
3462
3463 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07003464 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
3465 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07003466 else
Arend van Sprielac24be62012-10-22 10:36:23 -07003467 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
3468 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003469 if (ret == 0) {
3470 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
3471 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
3472 ret = cfg80211_testmode_reply(reply);
3473 }
3474 return ret;
3475}
3476#endif
3477
Hante Meuleman1a873342012-09-27 14:17:54 +02003478static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
3479{
Arend van Sprielac24be62012-10-22 10:36:23 -07003480 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003481 s32 err;
3482
3483 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003484 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003485 if (err < 0) {
3486 WL_ERR("auth error %d\n", err);
3487 return err;
3488 }
3489 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003490 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003491 if (err < 0) {
3492 WL_ERR("wsec error %d\n", err);
3493 return err;
3494 }
3495 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003496 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02003497 if (err < 0) {
3498 WL_ERR("wpa_auth error %d\n", err);
3499 return err;
3500 }
3501
3502 return 0;
3503}
3504
3505static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
3506{
3507 if (is_rsn_ie)
3508 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3509
3510 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3511}
3512
3513static s32
3514brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
3515 bool is_rsn_ie, s32 bssidx)
3516{
Arend van Sprielac24be62012-10-22 10:36:23 -07003517 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003518 u32 auth = 0; /* d11 open authentication */
3519 u16 count;
3520 s32 err = 0;
3521 s32 len = 0;
3522 u32 i;
3523 u32 wsec;
3524 u32 pval = 0;
3525 u32 gval = 0;
3526 u32 wpa_auth = 0;
3527 u32 offset;
3528 u8 *data;
3529 u16 rsn_cap;
3530 u32 wme_bss_disable;
3531
3532 WL_TRACE("Enter\n");
3533 if (wpa_ie == NULL)
3534 goto exit;
3535
3536 len = wpa_ie->len + TLV_HDR_LEN;
3537 data = (u8 *)wpa_ie;
3538 offset = 0;
3539 if (!is_rsn_ie)
3540 offset += VS_IE_FIXED_HDR_LEN;
3541 offset += WPA_IE_VERSION_LEN;
3542
3543 /* check for multicast cipher suite */
3544 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3545 err = -EINVAL;
3546 WL_ERR("no multicast cipher suite\n");
3547 goto exit;
3548 }
3549
3550 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3551 err = -EINVAL;
3552 WL_ERR("ivalid OUI\n");
3553 goto exit;
3554 }
3555 offset += TLV_OUI_LEN;
3556
3557 /* pick up multicast cipher */
3558 switch (data[offset]) {
3559 case WPA_CIPHER_NONE:
3560 gval = 0;
3561 break;
3562 case WPA_CIPHER_WEP_40:
3563 case WPA_CIPHER_WEP_104:
3564 gval = WEP_ENABLED;
3565 break;
3566 case WPA_CIPHER_TKIP:
3567 gval = TKIP_ENABLED;
3568 break;
3569 case WPA_CIPHER_AES_CCM:
3570 gval = AES_ENABLED;
3571 break;
3572 default:
3573 err = -EINVAL;
3574 WL_ERR("Invalid multi cast cipher info\n");
3575 goto exit;
3576 }
3577
3578 offset++;
3579 /* walk thru unicast cipher list and pick up what we recognize */
3580 count = data[offset] + (data[offset + 1] << 8);
3581 offset += WPA_IE_SUITE_COUNT_LEN;
3582 /* Check for unicast suite(s) */
3583 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3584 err = -EINVAL;
3585 WL_ERR("no unicast cipher suite\n");
3586 goto exit;
3587 }
3588 for (i = 0; i < count; i++) {
3589 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3590 err = -EINVAL;
3591 WL_ERR("ivalid OUI\n");
3592 goto exit;
3593 }
3594 offset += TLV_OUI_LEN;
3595 switch (data[offset]) {
3596 case WPA_CIPHER_NONE:
3597 break;
3598 case WPA_CIPHER_WEP_40:
3599 case WPA_CIPHER_WEP_104:
3600 pval |= WEP_ENABLED;
3601 break;
3602 case WPA_CIPHER_TKIP:
3603 pval |= TKIP_ENABLED;
3604 break;
3605 case WPA_CIPHER_AES_CCM:
3606 pval |= AES_ENABLED;
3607 break;
3608 default:
3609 WL_ERR("Ivalid unicast security info\n");
3610 }
3611 offset++;
3612 }
3613 /* walk thru auth management suite list and pick up what we recognize */
3614 count = data[offset] + (data[offset + 1] << 8);
3615 offset += WPA_IE_SUITE_COUNT_LEN;
3616 /* Check for auth key management suite(s) */
3617 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3618 err = -EINVAL;
3619 WL_ERR("no auth key mgmt suite\n");
3620 goto exit;
3621 }
3622 for (i = 0; i < count; i++) {
3623 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3624 err = -EINVAL;
3625 WL_ERR("ivalid OUI\n");
3626 goto exit;
3627 }
3628 offset += TLV_OUI_LEN;
3629 switch (data[offset]) {
3630 case RSN_AKM_NONE:
3631 WL_TRACE("RSN_AKM_NONE\n");
3632 wpa_auth |= WPA_AUTH_NONE;
3633 break;
3634 case RSN_AKM_UNSPECIFIED:
3635 WL_TRACE("RSN_AKM_UNSPECIFIED\n");
3636 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3637 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3638 break;
3639 case RSN_AKM_PSK:
3640 WL_TRACE("RSN_AKM_PSK\n");
3641 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3642 (wpa_auth |= WPA_AUTH_PSK);
3643 break;
3644 default:
3645 WL_ERR("Ivalid key mgmt info\n");
3646 }
3647 offset++;
3648 }
3649
3650 if (is_rsn_ie) {
3651 wme_bss_disable = 1;
3652 if ((offset + RSN_CAP_LEN) <= len) {
3653 rsn_cap = data[offset] + (data[offset + 1] << 8);
3654 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3655 wme_bss_disable = 0;
3656 }
3657 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003658 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003659 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003660 if (err < 0) {
3661 WL_ERR("wme_bss_disable error %d\n", err);
3662 goto exit;
3663 }
3664 }
3665 /* FOR WPS , set SES_OW_ENABLED */
3666 wsec = (pval | gval | SES_OW_ENABLED);
3667
3668 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003669 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003670 if (err < 0) {
3671 WL_ERR("auth error %d\n", err);
3672 goto exit;
3673 }
3674 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003675 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003676 if (err < 0) {
3677 WL_ERR("wsec error %d\n", err);
3678 goto exit;
3679 }
3680 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003681 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003682 if (err < 0) {
3683 WL_ERR("wpa_auth error %d\n", err);
3684 goto exit;
3685 }
3686
3687exit:
3688 return err;
3689}
3690
3691static s32
3692brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len,
3693 struct parsed_vndr_ies *vndr_ies)
3694{
3695 s32 err = 0;
3696 struct brcmf_vs_tlv *vndrie;
3697 struct brcmf_tlv *ie;
3698 struct parsed_vndr_ie_info *parsed_info;
3699 s32 remaining_len;
3700
3701 remaining_len = (s32)vndr_ie_len;
3702 memset(vndr_ies, 0, sizeof(*vndr_ies));
3703
3704 ie = (struct brcmf_tlv *)vndr_ie_buf;
3705 while (ie) {
3706 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3707 goto next;
3708 vndrie = (struct brcmf_vs_tlv *)ie;
3709 /* len should be bigger than OUI length + one */
3710 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
3711 WL_ERR("invalid vndr ie. length is too small %d\n",
3712 vndrie->len);
3713 goto next;
3714 }
3715 /* if wpa or wme ie, do not add ie */
3716 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3717 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3718 (vndrie->oui_type == WME_OUI_TYPE))) {
3719 WL_TRACE("Found WPA/WME oui. Do not add it\n");
3720 goto next;
3721 }
3722
3723 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3724
3725 /* save vndr ie information */
3726 parsed_info->ie_ptr = (char *)vndrie;
3727 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3728 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3729
3730 vndr_ies->count++;
3731
3732 WL_TRACE("** OUI %02x %02x %02x, type 0x%02x\n",
3733 parsed_info->vndrie.oui[0],
3734 parsed_info->vndrie.oui[1],
3735 parsed_info->vndrie.oui[2],
3736 parsed_info->vndrie.oui_type);
3737
3738 if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
3739 break;
3740next:
3741 remaining_len -= ie->len;
3742 if (remaining_len <= 2)
3743 ie = NULL;
3744 else
3745 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len);
3746 }
3747 return err;
3748}
3749
3750static u32
3751brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3752{
3753
3754 __le32 iecount_le;
3755 __le32 pktflag_le;
3756
3757 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3758 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3759
3760 iecount_le = cpu_to_le32(1);
3761 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3762
3763 pktflag_le = cpu_to_le32(pktflag);
3764 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3765
3766 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3767
3768 return ie_len + VNDR_IE_HDR_SIZE;
3769}
3770
Franky Lin3cb91f52012-10-10 11:13:08 -07003771static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003772brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
Arend van Spriel1d4fd8d2012-10-22 10:36:19 -07003773 struct net_device *ndev, s32 pktflag,
Hante Meuleman1a873342012-09-27 14:17:54 +02003774 u8 *vndr_ie_buf, u32 vndr_ie_len)
3775{
Arend van Sprielc1179032012-10-22 13:55:33 -07003776 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003777 struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003778 s32 err = 0;
3779 u8 *iovar_ie_buf;
3780 u8 *curr_ie_buf;
3781 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003782 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003783 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003784 u32 del_add_ie_buf_len = 0;
3785 u32 total_ie_buf_len = 0;
3786 u32 parsed_ie_buf_len = 0;
3787 struct parsed_vndr_ies old_vndr_ies;
3788 struct parsed_vndr_ies new_vndr_ies;
3789 struct parsed_vndr_ie_info *vndrie_info;
3790 s32 i;
3791 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003792 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003793
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07003794 WL_TRACE("bssidx %d, pktflag : 0x%02X\n",
3795 brcmf_ndev_bssidx(ndev), pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003796 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3797 if (!iovar_ie_buf)
3798 return -ENOMEM;
3799 curr_ie_buf = iovar_ie_buf;
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003800 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003801 switch (pktflag) {
3802 case VNDR_IE_PRBRSP_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003803 mgmt_ie_buf = saved_ie->probe_res_ie;
3804 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3805 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003806 break;
3807 case VNDR_IE_BEACON_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003808 mgmt_ie_buf = saved_ie->beacon_ie;
3809 mgmt_ie_len = &saved_ie->beacon_ie_len;
3810 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003811 break;
3812 default:
3813 err = -EPERM;
3814 WL_ERR("not suitable type\n");
3815 goto exit;
3816 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003817 } else {
3818 err = -EPERM;
3819 WL_ERR("not suitable type\n");
3820 goto exit;
3821 }
3822
3823 if (vndr_ie_len > mgmt_ie_buf_len) {
3824 err = -ENOMEM;
3825 WL_ERR("extra IE size too big\n");
3826 goto exit;
3827 }
3828
3829 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3830 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3831 ptr = curr_ie_buf;
3832 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3833 for (i = 0; i < new_vndr_ies.count; i++) {
3834 vndrie_info = &new_vndr_ies.ie_info[i];
3835 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3836 vndrie_info->ie_len);
3837 parsed_ie_buf_len += vndrie_info->ie_len;
3838 }
3839 }
3840
3841 if (mgmt_ie_buf != NULL) {
3842 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3843 (memcmp(mgmt_ie_buf, curr_ie_buf,
3844 parsed_ie_buf_len) == 0)) {
3845 WL_TRACE("Previous mgmt IE is equals to current IE");
3846 goto exit;
3847 }
3848
3849 /* parse old vndr_ie */
3850 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3851
3852 /* make a command to delete old ie */
3853 for (i = 0; i < old_vndr_ies.count; i++) {
3854 vndrie_info = &old_vndr_ies.ie_info[i];
3855
3856 WL_TRACE("DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3857 vndrie_info->vndrie.id,
3858 vndrie_info->vndrie.len,
3859 vndrie_info->vndrie.oui[0],
3860 vndrie_info->vndrie.oui[1],
3861 vndrie_info->vndrie.oui[2]);
3862
3863 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3864 vndrie_info->ie_ptr,
3865 vndrie_info->ie_len,
3866 "del");
3867 curr_ie_buf += del_add_ie_buf_len;
3868 total_ie_buf_len += del_add_ie_buf_len;
3869 }
3870 }
3871
3872 *mgmt_ie_len = 0;
3873 /* Add if there is any extra IE */
3874 if (mgmt_ie_buf && parsed_ie_buf_len) {
3875 ptr = mgmt_ie_buf;
3876
3877 remained_buf_len = mgmt_ie_buf_len;
3878
3879 /* make a command to add new ie */
3880 for (i = 0; i < new_vndr_ies.count; i++) {
3881 vndrie_info = &new_vndr_ies.ie_info[i];
3882
3883 WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3884 vndrie_info->vndrie.id,
3885 vndrie_info->vndrie.len,
3886 vndrie_info->vndrie.oui[0],
3887 vndrie_info->vndrie.oui[1],
3888 vndrie_info->vndrie.oui[2]);
3889
3890 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3891 vndrie_info->ie_ptr,
3892 vndrie_info->ie_len,
3893 "add");
3894 /* verify remained buf size before copy data */
3895 remained_buf_len -= vndrie_info->ie_len;
3896 if (remained_buf_len < 0) {
3897 WL_ERR("no space in mgmt_ie_buf: len left %d",
3898 remained_buf_len);
3899 break;
3900 }
3901
3902 /* save the parsed IE in wl struct */
3903 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3904 vndrie_info->ie_len);
3905 *mgmt_ie_len += vndrie_info->ie_len;
3906
3907 curr_ie_buf += del_add_ie_buf_len;
3908 total_ie_buf_len += del_add_ie_buf_len;
3909 }
3910 }
3911 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003912 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003913 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003914 if (err)
3915 WL_ERR("vndr ie set error : %d\n", err);
3916 }
3917
3918exit:
3919 kfree(iovar_ie_buf);
3920 return err;
3921}
3922
3923static s32
3924brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3925 struct cfg80211_ap_settings *settings)
3926{
3927 s32 ie_offset;
Arend van Sprielac24be62012-10-22 10:36:23 -07003928 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003929 struct brcmf_tlv *ssid_ie;
3930 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003931 s32 err = -EPERM;
3932 struct brcmf_tlv *rsn_ie;
3933 struct brcmf_vs_tlv *wpa_ie;
3934 struct brcmf_join_params join_params;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003935 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02003936 s32 bssidx = 0;
3937
3938 WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3939 settings->channel_type, settings->beacon_interval,
3940 settings->dtim_period);
3941 WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n",
3942 settings->ssid, settings->ssid_len, settings->auth_type,
3943 settings->inactivity_timeout);
3944
Arend van Sprielc1179032012-10-22 13:55:33 -07003945 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003946 WL_ERR("Not in AP creation mode\n");
3947 return -EPERM;
3948 }
3949
3950 memset(&ssid_le, 0, sizeof(ssid_le));
3951 if (settings->ssid == NULL || settings->ssid_len == 0) {
3952 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3953 ssid_ie = brcmf_parse_tlvs(
3954 (u8 *)&settings->beacon.head[ie_offset],
3955 settings->beacon.head_len - ie_offset,
3956 WLAN_EID_SSID);
3957 if (!ssid_ie)
3958 return -EINVAL;
3959
3960 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3961 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
3962 WL_TRACE("SSID is (%s) in Head\n", ssid_le.SSID);
3963 } else {
3964 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3965 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3966 }
3967
3968 brcmf_set_mpc(ndev, 0);
Arend van Sprielac24be62012-10-22 10:36:23 -07003969 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003970 if (err < 0) {
3971 WL_ERR("BRCMF_C_DOWN error %d\n", err);
3972 goto exit;
3973 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003974 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003975 if (err < 0) {
3976 WL_ERR("SET INFRA error %d\n", err);
3977 goto exit;
3978 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003979 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003980 if (err < 0) {
3981 WL_ERR("setting AP mode failed %d\n", err);
3982 goto exit;
3983 }
3984
3985 /* find the RSN_IE */
3986 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3987 settings->beacon.tail_len, WLAN_EID_RSN);
3988
3989 /* find the WPA_IE */
3990 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3991 settings->beacon.tail_len);
3992
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003993 kfree(cfg->ap_info->rsn_ie);
3994 cfg->ap_info->rsn_ie = NULL;
3995 kfree(cfg->ap_info->wpa_ie);
3996 cfg->ap_info->wpa_ie = NULL;
Hante Meuleman1a873342012-09-27 14:17:54 +02003997
3998 if ((wpa_ie != NULL || rsn_ie != NULL)) {
3999 WL_TRACE("WPA(2) IE is found\n");
4000 if (wpa_ie != NULL) {
4001 /* WPA IE */
4002 err = brcmf_configure_wpaie(ndev, wpa_ie, false,
4003 bssidx);
4004 if (err < 0)
4005 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004006 cfg->ap_info->wpa_ie = kmemdup(wpa_ie,
Hante Meuleman1a873342012-09-27 14:17:54 +02004007 wpa_ie->len +
4008 TLV_HDR_LEN,
4009 GFP_KERNEL);
4010 } else {
4011 /* RSN IE */
4012 err = brcmf_configure_wpaie(ndev,
4013 (struct brcmf_vs_tlv *)rsn_ie, true, bssidx);
4014 if (err < 0)
4015 goto exit;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004016 cfg->ap_info->rsn_ie = kmemdup(rsn_ie,
Hante Meuleman1a873342012-09-27 14:17:54 +02004017 rsn_ie->len +
4018 TLV_HDR_LEN,
4019 GFP_KERNEL);
4020 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004021 cfg->ap_info->security_mode = true;
Hante Meuleman1a873342012-09-27 14:17:54 +02004022 } else {
4023 WL_TRACE("No WPA(2) IEs found\n");
4024 brcmf_configure_opensecurity(ndev, bssidx);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004025 cfg->ap_info->security_mode = false;
Hante Meuleman1a873342012-09-27 14:17:54 +02004026 }
4027 /* Set Beacon IEs to FW */
Arend van Spriel1d4fd8d2012-10-22 10:36:19 -07004028 err = brcmf_set_management_ie(cfg, ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02004029 VNDR_IE_BEACON_FLAG,
4030 (u8 *)settings->beacon.tail,
4031 settings->beacon.tail_len);
4032 if (err)
4033 WL_ERR("Set Beacon IE Failed\n");
4034 else
4035 WL_TRACE("Applied Vndr IEs for Beacon\n");
4036
4037 /* Set Probe Response IEs to FW */
Arend van Spriel1d4fd8d2012-10-22 10:36:19 -07004038 err = brcmf_set_management_ie(cfg, ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02004039 VNDR_IE_PRBRSP_FLAG,
4040 (u8 *)settings->beacon.proberesp_ies,
4041 settings->beacon.proberesp_ies_len);
4042 if (err)
4043 WL_ERR("Set Probe Resp IE Failed\n");
4044 else
4045 WL_TRACE("Applied Vndr IEs for Probe Resp\n");
4046
4047 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004048 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004049 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02004050 if (err < 0) {
4051 WL_ERR("Beacon Interval Set Error, %d\n", err);
4052 goto exit;
4053 }
4054 }
4055 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004056 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004057 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02004058 if (err < 0) {
4059 WL_ERR("DTIM Interval Set Error, %d\n", err);
4060 goto exit;
4061 }
4062 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004063 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02004064 if (err < 0) {
4065 WL_ERR("BRCMF_C_UP error (%d)\n", err);
4066 goto exit;
4067 }
4068
4069 memset(&join_params, 0, sizeof(join_params));
4070 /* join parameters starts with ssid */
4071 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
4072 /* create softap */
Arend van Sprielac24be62012-10-22 10:36:23 -07004073 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
4074 &join_params, sizeof(join_params));
Hante Meuleman1a873342012-09-27 14:17:54 +02004075 if (err < 0) {
4076 WL_ERR("SET SSID error (%d)\n", err);
4077 goto exit;
4078 }
Arend van Sprielc1179032012-10-22 13:55:33 -07004079 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4080 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02004081
4082exit:
4083 if (err)
4084 brcmf_set_mpc(ndev, 1);
4085 return err;
4086}
4087
4088static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
4089{
Arend van Sprielc1179032012-10-22 13:55:33 -07004090 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004091 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Hante Meuleman1a873342012-09-27 14:17:54 +02004092 s32 err = -EPERM;
4093
4094 WL_TRACE("Enter\n");
4095
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004096 if (cfg->conf->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02004097 /* Due to most likely deauths outstanding we sleep */
4098 /* first to make sure they get processed by fw. */
4099 msleep(400);
Arend van Sprielac24be62012-10-22 10:36:23 -07004100 err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
4101 BRCMF_C_SET_AP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02004102 if (err < 0) {
4103 WL_ERR("setting AP mode failed %d\n", err);
4104 goto exit;
4105 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004106 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02004107 if (err < 0) {
4108 WL_ERR("BRCMF_C_UP error %d\n", err);
4109 goto exit;
4110 }
4111 brcmf_set_mpc(ndev, 1);
Arend van Sprielc1179032012-10-22 13:55:33 -07004112 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
4113 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02004114 }
4115exit:
4116 return err;
4117}
4118
4119static int
4120brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
4121 u8 *mac)
4122{
4123 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004124 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02004125 s32 err;
4126
4127 if (!mac)
4128 return -EFAULT;
4129
4130 WL_TRACE("Enter %pM\n", mac);
4131
Arend van Sprielce81e312012-10-22 13:55:37 -07004132 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02004133 return -EIO;
4134
4135 memcpy(&scbval.ea, mac, ETH_ALEN);
4136 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07004137 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004138 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02004139 if (err)
4140 WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
4141
4142 WL_TRACE("Exit\n");
4143 return err;
4144}
4145
Arend van Spriel5b435de2011-10-05 13:19:03 +02004146static struct cfg80211_ops wl_cfg80211_ops = {
4147 .change_virtual_intf = brcmf_cfg80211_change_iface,
4148 .scan = brcmf_cfg80211_scan,
4149 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
4150 .join_ibss = brcmf_cfg80211_join_ibss,
4151 .leave_ibss = brcmf_cfg80211_leave_ibss,
4152 .get_station = brcmf_cfg80211_get_station,
4153 .set_tx_power = brcmf_cfg80211_set_tx_power,
4154 .get_tx_power = brcmf_cfg80211_get_tx_power,
4155 .add_key = brcmf_cfg80211_add_key,
4156 .del_key = brcmf_cfg80211_del_key,
4157 .get_key = brcmf_cfg80211_get_key,
4158 .set_default_key = brcmf_cfg80211_config_default_key,
4159 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
4160 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
4161 .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
4162 .connect = brcmf_cfg80211_connect,
4163 .disconnect = brcmf_cfg80211_disconnect,
4164 .suspend = brcmf_cfg80211_suspend,
4165 .resume = brcmf_cfg80211_resume,
4166 .set_pmksa = brcmf_cfg80211_set_pmksa,
4167 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004168 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02004169 .start_ap = brcmf_cfg80211_start_ap,
4170 .stop_ap = brcmf_cfg80211_stop_ap,
4171 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02004172#ifndef CONFIG_BRCMISCAN
4173 /* scheduled scan need e-scan, which is mutual exclusive with i-scan */
4174 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
4175 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
4176#endif
Arend van Sprielcbaa1772012-08-30 19:43:02 +02004177#ifdef CONFIG_NL80211_TESTMODE
4178 .testmode_cmd = brcmf_cfg80211_testmode
4179#endif
Arend van Spriel5b435de2011-10-05 13:19:03 +02004180};
4181
4182static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
4183{
4184 s32 err = 0;
4185
4186 switch (mode) {
4187 case WL_MODE_BSS:
4188 return NL80211_IFTYPE_STATION;
4189 case WL_MODE_IBSS:
4190 return NL80211_IFTYPE_ADHOC;
4191 default:
4192 return NL80211_IFTYPE_UNSPECIFIED;
4193 }
4194
4195 return err;
4196}
4197
Arend van Spriele5806072012-09-19 22:21:08 +02004198static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
4199{
4200#ifndef CONFIG_BRCMFISCAN
4201 /* scheduled scan settings */
4202 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
4203 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
4204 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
4205 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
4206#endif
4207}
4208
Arend van Spriel3eacf862012-10-22 13:55:30 -07004209static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004210{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004211 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004212 s32 err = 0;
4213
Arend van Spriel3eacf862012-10-22 13:55:30 -07004214 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
4215 if (!wiphy) {
Joe Perchesbfeb4db2012-01-15 00:38:45 -08004216 WL_ERR("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07004217 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004218 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004219 set_wiphy_dev(wiphy, phydev);
4220 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
4221 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4222 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4223 BIT(NL80211_IFTYPE_ADHOC) |
4224 BIT(NL80211_IFTYPE_AP);
4225 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4226 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
Arend van Spriel5b435de2011-10-05 13:19:03 +02004227 * it as 11a by default.
4228 * This will be updated with
4229 * 11n phy tables in
4230 * "ifconfig up"
4231 * if phy has 11n capability
4232 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07004233 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4234 wiphy->cipher_suites = __wl_cipher_suites;
4235 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
4236 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
Arend van Spriel5b435de2011-10-05 13:19:03 +02004237 * save mode
4238 * by default
4239 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07004240 brcmf_wiphy_pno_params(wiphy);
4241 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004242 if (err < 0) {
Joe Perchesbfeb4db2012-01-15 00:38:45 -08004243 WL_ERR("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004244 wiphy_free(wiphy);
4245 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004246 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004247 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004248}
4249
Arend van Spriel3eacf862012-10-22 13:55:30 -07004250static
4251struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
4252 struct net_device *netdev,
4253 s32 mode, bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004254{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004255 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004256
Arend van Spriel3eacf862012-10-22 13:55:30 -07004257 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
4258 return ERR_PTR(-ENOSPC);
4259
4260 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
4261 if (!vif)
4262 return ERR_PTR(-ENOMEM);
4263
4264 vif->wdev.wiphy = cfg->wiphy;
4265 vif->wdev.netdev = netdev;
4266 vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
4267
4268 if (netdev) {
4269 vif->ifp = netdev_priv(netdev);
4270 netdev->ieee80211_ptr = &vif->wdev;
4271 SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004272 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07004273
4274 vif->mode = mode;
4275 vif->pm_block = pm_block;
4276 vif->roam_off = -1;
4277
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004278 brcmf_init_prof(&vif->profile);
4279
Arend van Spriel3eacf862012-10-22 13:55:30 -07004280 list_add_tail(&vif->list, &cfg->vif_list);
4281 cfg->vif_cnt++;
4282 return vif;
4283}
4284
4285static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
4286{
4287 struct brcmf_cfg80211_info *cfg;
4288 struct wiphy *wiphy;
4289
4290 wiphy = vif->wdev.wiphy;
4291 cfg = wiphy_priv(wiphy);
4292 list_del(&vif->list);
4293 cfg->vif_cnt--;
4294
4295 kfree(vif);
4296 if (!cfg->vif_cnt) {
4297 wiphy_unregister(wiphy);
4298 wiphy_free(wiphy);
4299 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004300}
4301
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004302static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004303 const struct brcmf_event_msg *e)
4304{
4305 u32 event = be32_to_cpu(e->event_type);
4306 u32 status = be32_to_cpu(e->status);
4307
4308 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
4309 WL_CONN("Processing set ssid\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004310 cfg->link_up = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004311 return true;
4312 }
4313
4314 return false;
4315}
4316
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004317static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004318 const struct brcmf_event_msg *e)
4319{
4320 u32 event = be32_to_cpu(e->event_type);
4321 u16 flags = be16_to_cpu(e->flags);
4322
4323 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
4324 WL_CONN("Processing link down\n");
4325 return true;
4326 }
4327 return false;
4328}
4329
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004330static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004331 const struct brcmf_event_msg *e)
4332{
4333 u32 event = be32_to_cpu(e->event_type);
4334 u32 status = be32_to_cpu(e->status);
4335
4336 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
4337 WL_CONN("Processing Link %s & no network found\n",
4338 be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
4339 "up" : "down");
4340 return true;
4341 }
4342
4343 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
4344 WL_CONN("Processing connecting & no network found\n");
4345 return true;
4346 }
4347
4348 return false;
4349}
4350
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004351static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004352{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004353 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004354
4355 kfree(conn_info->req_ie);
4356 conn_info->req_ie = NULL;
4357 conn_info->req_ie_len = 0;
4358 kfree(conn_info->resp_ie);
4359 conn_info->resp_ie = NULL;
4360 conn_info->resp_ie_len = 0;
4361}
4362
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004363static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004364{
Arend van Sprielac24be62012-10-22 10:36:23 -07004365 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004366 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004367 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004368 u32 req_len;
4369 u32 resp_len;
4370 s32 err = 0;
4371
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004372 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004373
Arend van Sprielac24be62012-10-22 10:36:23 -07004374 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
4375 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004376 if (err) {
4377 WL_ERR("could not get assoc info (%d)\n", err);
4378 return err;
4379 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004380 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004381 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02004382 req_len = le32_to_cpu(assoc_info->req_len);
4383 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004384 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004385 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004386 cfg->extra_buf,
4387 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004388 if (err) {
4389 WL_ERR("could not get assoc req (%d)\n", err);
4390 return err;
4391 }
4392 conn_info->req_ie_len = req_len;
4393 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004394 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004395 GFP_KERNEL);
4396 } else {
4397 conn_info->req_ie_len = 0;
4398 conn_info->req_ie = NULL;
4399 }
4400 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004401 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004402 cfg->extra_buf,
4403 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004404 if (err) {
4405 WL_ERR("could not get assoc resp (%d)\n", err);
4406 return err;
4407 }
4408 conn_info->resp_ie_len = resp_len;
4409 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004410 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004411 GFP_KERNEL);
4412 } else {
4413 conn_info->resp_ie_len = 0;
4414 conn_info->resp_ie = NULL;
4415 }
4416 WL_CONN("req len (%d) resp len (%d)\n",
4417 conn_info->req_ie_len, conn_info->resp_ie_len);
4418
4419 return err;
4420}
4421
4422static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004423brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004424 struct net_device *ndev,
4425 const struct brcmf_event_msg *e)
4426{
Arend van Sprielc1179032012-10-22 13:55:33 -07004427 struct brcmf_if *ifp = netdev_priv(ndev);
4428 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004429 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4430 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07004431 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004432 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07004433 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004434 u32 freq;
4435 s32 err = 0;
4436 u32 target_channel;
Franky Lina180b832012-10-10 11:13:09 -07004437 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004438
4439 WL_TRACE("Enter\n");
4440
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004441 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004442 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004443 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004444
Franky Lina180b832012-10-10 11:13:09 -07004445 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4446 if (buf == NULL) {
4447 err = -ENOMEM;
4448 goto done;
4449 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004450
Franky Lina180b832012-10-10 11:13:09 -07004451 /* data sent to dongle has to be little endian */
4452 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07004453 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07004454 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07004455
4456 if (err)
4457 goto done;
4458
4459 bi = (struct brcmf_bss_info_le *)(buf + 4);
4460 target_channel = bi->ctl_ch ? bi->ctl_ch :
4461 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004462
4463 if (target_channel <= CH_MAX_2G_CHANNEL)
4464 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4465 else
4466 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4467
4468 freq = ieee80211_channel_to_frequency(target_channel, band->band);
4469 notify_channel = ieee80211_get_channel(wiphy, freq);
4470
Franky Lina180b832012-10-10 11:13:09 -07004471done:
4472 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02004473 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004474 conn_info->req_ie, conn_info->req_ie_len,
4475 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4476 WL_CONN("Report roaming result\n");
4477
Arend van Sprielc1179032012-10-22 13:55:33 -07004478 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004479 WL_TRACE("Exit\n");
4480 return err;
4481}
4482
4483static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004484brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004485 struct net_device *ndev, const struct brcmf_event_msg *e,
4486 bool completed)
4487{
Arend van Sprielc1179032012-10-22 13:55:33 -07004488 struct brcmf_if *ifp = netdev_priv(ndev);
4489 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004490 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004491 s32 err = 0;
4492
4493 WL_TRACE("Enter\n");
4494
Arend van Sprielc1179032012-10-22 13:55:33 -07004495 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4496 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004497 if (completed) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004498 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004499 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004500 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004501 }
4502 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02004503 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004504 conn_info->req_ie,
4505 conn_info->req_ie_len,
4506 conn_info->resp_ie,
4507 conn_info->resp_ie_len,
4508 completed ? WLAN_STATUS_SUCCESS :
4509 WLAN_STATUS_AUTH_TIMEOUT,
4510 GFP_KERNEL);
4511 if (completed)
Arend van Sprielc1179032012-10-22 13:55:33 -07004512 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4513 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004514 WL_CONN("Report connect result - connection %s\n",
4515 completed ? "succeeded" : "failed");
4516 }
4517 WL_TRACE("Exit\n");
4518 return err;
4519}
4520
4521static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004522brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02004523 struct net_device *ndev,
4524 const struct brcmf_event_msg *e, void *data)
4525{
4526 s32 err = 0;
4527 u32 event = be32_to_cpu(e->event_type);
4528 u32 reason = be32_to_cpu(e->reason);
4529 u32 len = be32_to_cpu(e->datalen);
4530 static int generation;
4531
4532 struct station_info sinfo;
4533
4534 WL_CONN("event %d, reason %d\n", event, reason);
4535 memset(&sinfo, 0, sizeof(sinfo));
4536
4537 sinfo.filled = 0;
4538 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4539 reason == BRCMF_E_STATUS_SUCCESS) {
4540 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4541 if (!data) {
4542 WL_ERR("No IEs present in ASSOC/REASSOC_IND");
4543 return -EINVAL;
4544 }
4545 sinfo.assoc_req_ies = data;
4546 sinfo.assoc_req_ies_len = len;
4547 generation++;
4548 sinfo.generation = generation;
4549 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
4550 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4551 (event == BRCMF_E_DEAUTH_IND) ||
4552 (event == BRCMF_E_DEAUTH)) {
4553 generation++;
4554 sinfo.generation = generation;
4555 cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
4556 }
4557 return err;
4558}
4559
4560static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004561brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004562 struct net_device *ndev,
4563 const struct brcmf_event_msg *e, void *data)
4564{
Arend van Sprielc1179032012-10-22 13:55:33 -07004565 struct brcmf_if *ifp = netdev_priv(ndev);
4566 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004567 s32 err = 0;
4568
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004569 if (cfg->conf->mode == WL_MODE_AP) {
4570 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4571 } else if (brcmf_is_linkup(cfg, e)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004572 WL_CONN("Linkup\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004573 if (brcmf_is_ibssmode(cfg)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004574 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004575 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004576 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004577 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4578 &ifp->vif->sme_state);
4579 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4580 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004581 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004582 brcmf_bss_connect_done(cfg, ndev, e, true);
4583 } else if (brcmf_is_linkdown(cfg, e)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004584 WL_CONN("Linkdown\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004585 if (brcmf_is_ibssmode(cfg)) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004586 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4587 &ifp->vif->sme_state);
4588 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4589 &ifp->vif->sme_state))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004590 brcmf_link_down(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004591 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004592 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004593 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4594 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004595 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004596 GFP_KERNEL);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004597 brcmf_link_down(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004598 }
4599 }
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004600 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004601 } else if (brcmf_is_nonetwork(cfg, e)) {
4602 if (brcmf_is_ibssmode(cfg))
Arend van Sprielc1179032012-10-22 13:55:33 -07004603 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4604 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004605 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004606 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004607 }
4608
4609 return err;
4610}
4611
4612static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004613brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004614 struct net_device *ndev,
4615 const struct brcmf_event_msg *e, void *data)
4616{
Arend van Sprielc1179032012-10-22 13:55:33 -07004617 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004618 s32 err = 0;
4619 u32 event = be32_to_cpu(e->event_type);
4620 u32 status = be32_to_cpu(e->status);
4621
4622 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004623 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004624 brcmf_bss_roaming_done(cfg, ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004625 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004626 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004627 }
4628
4629 return err;
4630}
4631
4632static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004633brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004634 struct net_device *ndev,
4635 const struct brcmf_event_msg *e, void *data)
4636{
4637 u16 flags = be16_to_cpu(e->flags);
4638 enum nl80211_key_type key_type;
4639
4640 if (flags & BRCMF_EVENT_MSG_GROUP)
4641 key_type = NL80211_KEYTYPE_GROUP;
4642 else
4643 key_type = NL80211_KEYTYPE_PAIRWISE;
4644
4645 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
4646 NULL, GFP_KERNEL);
4647
4648 return 0;
4649}
4650
4651static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004652brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004653 struct net_device *ndev,
4654 const struct brcmf_event_msg *e, void *data)
4655{
Arend van Sprielc1179032012-10-22 13:55:33 -07004656 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004657 struct brcmf_channel_info_le channel_inform_le;
4658 struct brcmf_scan_results_le *bss_list_le;
4659 u32 len = WL_SCAN_BUF_MAX;
4660 s32 err = 0;
4661 bool scan_abort = false;
4662 u32 scan_channel;
4663
4664 WL_TRACE("Enter\n");
4665
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004666 if (cfg->iscan_on && cfg->iscan_kickstart) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004667 WL_TRACE("Exit\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004668 return brcmf_wakeup_iscan(cfg_to_iscan(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004669 }
4670
Arend van Sprielc1179032012-10-22 13:55:33 -07004671 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004672 WL_ERR("Scan complete while device not scanning\n");
4673 scan_abort = true;
4674 err = -EINVAL;
4675 goto scan_done_out;
4676 }
4677
Arend van Sprielc1179032012-10-22 13:55:33 -07004678 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004679 &channel_inform_le,
4680 sizeof(channel_inform_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004681 if (err) {
4682 WL_ERR("scan busy (%d)\n", err);
4683 scan_abort = true;
4684 goto scan_done_out;
4685 }
4686 scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
4687 if (scan_channel)
4688 WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004689 cfg->bss_list = cfg->scan_results;
4690 bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004691
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004692 memset(cfg->scan_results, 0, len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004693 bss_list_le->buflen = cpu_to_le32(len);
Arend van Sprielc1179032012-10-22 13:55:33 -07004694 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004695 cfg->scan_results, len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004696 if (err) {
4697 WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
4698 err = -EINVAL;
4699 scan_abort = true;
4700 goto scan_done_out;
4701 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004702 cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
4703 cfg->scan_results->version = le32_to_cpu(bss_list_le->version);
4704 cfg->scan_results->count = le32_to_cpu(bss_list_le->count);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004705
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004706 err = brcmf_inform_bss(cfg);
Hante Meuleman35aafa92012-09-11 21:18:49 +02004707 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004708 scan_abort = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004709
4710scan_done_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004711 if (cfg->scan_request) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02004712 WL_SCAN("calling cfg80211_scan_done\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004713 cfg80211_scan_done(cfg->scan_request, scan_abort);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004714 brcmf_set_mpc(ndev, 1);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004715 cfg->scan_request = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004716 }
4717
4718 WL_TRACE("Exit\n");
4719
4720 return err;
4721}
4722
4723static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4724{
4725 conf->mode = (u32)-1;
4726 conf->frag_threshold = (u32)-1;
4727 conf->rts_threshold = (u32)-1;
4728 conf->retry_short = (u32)-1;
4729 conf->retry_long = (u32)-1;
4730 conf->tx_power = -1;
4731}
4732
4733static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
4734{
4735 memset(el, 0, sizeof(*el));
4736 el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;
4737 el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
Hante Meuleman1a873342012-09-27 14:17:54 +02004738 el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status;
4739 el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status;
4740 el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status;
4741 el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status;
4742 el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004743 el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
4744 el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
4745 el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
Arend van Spriele5806072012-09-19 22:21:08 +02004746 el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004747}
4748
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004749static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004750{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004751 kfree(cfg->scan_results);
4752 cfg->scan_results = NULL;
4753 kfree(cfg->bss_info);
4754 cfg->bss_info = NULL;
4755 kfree(cfg->conf);
4756 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004757 kfree(cfg->scan_req_int);
4758 cfg->scan_req_int = NULL;
4759 kfree(cfg->escan_ioctl_buf);
4760 cfg->escan_ioctl_buf = NULL;
4761 kfree(cfg->dcmd_buf);
4762 cfg->dcmd_buf = NULL;
4763 kfree(cfg->extra_buf);
4764 cfg->extra_buf = NULL;
4765 kfree(cfg->iscan);
4766 cfg->iscan = NULL;
4767 kfree(cfg->pmk_list);
4768 cfg->pmk_list = NULL;
4769 if (cfg->ap_info) {
4770 kfree(cfg->ap_info->wpa_ie);
4771 kfree(cfg->ap_info->rsn_ie);
4772 kfree(cfg->ap_info);
4773 cfg->ap_info = NULL;
Hante Meuleman1a873342012-09-27 14:17:54 +02004774 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004775}
4776
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004777static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004778{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004779 cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
4780 if (!cfg->scan_results)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004781 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004782 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4783 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004784 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004785 cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4786 if (!cfg->bss_info)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004787 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004788 cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int),
Arend van Spriel5b435de2011-10-05 13:19:03 +02004789 GFP_KERNEL);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004790 if (!cfg->scan_req_int)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004791 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004792 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4793 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004794 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004795 cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
4796 if (!cfg->dcmd_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004797 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004798 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4799 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004800 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004801 cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL);
4802 if (!cfg->iscan)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004803 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004804 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4805 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004806 goto init_priv_mem_out;
4807
4808 return 0;
4809
4810init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004811 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004812
4813 return -ENOMEM;
4814}
4815
4816/*
4817* retrieve first queued event from head
4818*/
4819
4820static struct brcmf_cfg80211_event_q *brcmf_deq_event(
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004821 struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004822{
4823 struct brcmf_cfg80211_event_q *e = NULL;
4824
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004825 spin_lock_irq(&cfg->evt_q_lock);
4826 if (!list_empty(&cfg->evt_q_list)) {
4827 e = list_first_entry(&cfg->evt_q_list,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004828 struct brcmf_cfg80211_event_q, evt_q_list);
4829 list_del(&e->evt_q_list);
4830 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004831 spin_unlock_irq(&cfg->evt_q_lock);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004832
4833 return e;
4834}
4835
4836/*
Arend van Sprielbcbec9e2012-02-09 21:09:06 +01004837* push event to tail of the queue
4838*
4839* remark: this function may not sleep as it is called in atomic context.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004840*/
4841
4842static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004843brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event,
Hante Meulemanc4fdb052012-09-11 21:18:47 +02004844 const struct brcmf_event_msg *msg, void *data)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004845{
4846 struct brcmf_cfg80211_event_q *e;
4847 s32 err = 0;
Arend van Sprielcf440662012-02-09 21:09:07 +01004848 ulong flags;
Hante Meulemanc4fdb052012-09-11 21:18:47 +02004849 u32 data_len;
4850 u32 total_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004851
Hante Meulemanc4fdb052012-09-11 21:18:47 +02004852 total_len = sizeof(struct brcmf_cfg80211_event_q);
4853 if (data)
4854 data_len = be32_to_cpu(msg->datalen);
4855 else
4856 data_len = 0;
4857 total_len += data_len;
4858 e = kzalloc(total_len, GFP_ATOMIC);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004859 if (!e)
4860 return -ENOMEM;
4861
4862 e->etype = event;
4863 memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
Hante Meulemanc4fdb052012-09-11 21:18:47 +02004864 if (data)
4865 memcpy(&e->edata, data, data_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004866
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004867 spin_lock_irqsave(&cfg->evt_q_lock, flags);
4868 list_add_tail(&e->evt_q_list, &cfg->evt_q_list);
4869 spin_unlock_irqrestore(&cfg->evt_q_lock, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004870
4871 return err;
4872}
4873
4874static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
4875{
4876 kfree(e);
4877}
4878
4879static void brcmf_cfg80211_event_handler(struct work_struct *work)
4880{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004881 struct brcmf_cfg80211_info *cfg =
4882 container_of(work, struct brcmf_cfg80211_info,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004883 event_work);
4884 struct brcmf_cfg80211_event_q *e;
4885
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004886 e = brcmf_deq_event(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004887 if (unlikely(!e)) {
4888 WL_ERR("event queue empty...\n");
4889 return;
4890 }
4891
4892 do {
4893 WL_INFO("event type (%d)\n", e->etype);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004894 if (cfg->el.handler[e->etype])
4895 cfg->el.handler[e->etype](cfg,
4896 cfg_to_ndev(cfg),
Arend van Spriel5b435de2011-10-05 13:19:03 +02004897 &e->emsg, e->edata);
4898 else
4899 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
4900 brcmf_put_event(e);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004901 } while ((e = brcmf_deq_event(cfg)));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004902
4903}
4904
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004905static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004906{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004907 spin_lock_init(&cfg->evt_q_lock);
4908 INIT_LIST_HEAD(&cfg->evt_q_list);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004909}
4910
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004911static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004912{
4913 struct brcmf_cfg80211_event_q *e;
4914
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004915 spin_lock_irq(&cfg->evt_q_lock);
4916 while (!list_empty(&cfg->evt_q_list)) {
4917 e = list_first_entry(&cfg->evt_q_list,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004918 struct brcmf_cfg80211_event_q, evt_q_list);
4919 list_del(&e->evt_q_list);
4920 kfree(e);
4921 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004922 spin_unlock_irq(&cfg->evt_q_lock);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004923}
4924
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004925static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004926{
4927 s32 err = 0;
4928
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004929 cfg->scan_request = NULL;
4930 cfg->pwr_save = true;
Hante Meulemane756af52012-09-11 21:18:52 +02004931#ifdef CONFIG_BRCMISCAN
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004932 cfg->iscan_on = true; /* iscan on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004933 we enable iscan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004934 cfg->escan_on = false; /* escan on & off switch.
Hante Meulemane756af52012-09-11 21:18:52 +02004935 we disable escan per default */
4936#else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004937 cfg->iscan_on = false; /* iscan on & off switch.
Hante Meulemane756af52012-09-11 21:18:52 +02004938 we disable iscan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004939 cfg->escan_on = true; /* escan on & off switch.
Hante Meulemane756af52012-09-11 21:18:52 +02004940 we enable escan per default */
4941#endif
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004942 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004943 we enable roam per default */
4944
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004945 cfg->iscan_kickstart = false;
4946 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004947 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004948 cfg->dongle_up = false; /* dongle is not up yet */
4949 brcmf_init_eq(cfg);
4950 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004951 if (err)
4952 return err;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004953 INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler);
4954 brcmf_init_eloop_handler(&cfg->el);
4955 mutex_init(&cfg->usr_sync);
4956 err = brcmf_init_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004957 if (err)
4958 return err;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004959 brcmf_init_escan(cfg);
4960 brcmf_init_conf(cfg->conf);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004961 brcmf_link_down(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004962
4963 return err;
4964}
4965
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004966static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004967{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004968 cancel_work_sync(&cfg->event_work);
4969 cfg->dongle_up = false; /* dongle down */
4970 brcmf_flush_eq(cfg);
4971 brcmf_link_down(cfg);
4972 brcmf_abort_scanning(cfg);
4973 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004974}
4975
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004976struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004977{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004978 struct net_device *ndev = drvr->iflist[0]->ndev;
4979 struct device *busdev = drvr->dev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004980 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004981 struct wiphy *wiphy;
4982 struct brcmf_cfg80211_vif *vif;
4983 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004984 s32 err = 0;
4985
4986 if (!ndev) {
4987 WL_ERR("ndev is invalid\n");
4988 return NULL;
4989 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004990
Arend van Spriel3eacf862012-10-22 13:55:30 -07004991 ifp = netdev_priv(ndev);
4992 wiphy = brcmf_setup_wiphy(busdev);
4993 if (IS_ERR(wiphy))
4994 return NULL;
4995
4996 cfg = wiphy_priv(wiphy);
4997 cfg->wiphy = wiphy;
4998 cfg->pub = drvr;
4999 INIT_LIST_HEAD(&cfg->vif_list);
5000
5001 vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
5002 if (IS_ERR(vif)) {
5003 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005004 return NULL;
5005 }
5006
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005007 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005008 if (err) {
5009 WL_ERR("Failed to init iwm_priv (%d)\n", err);
5010 goto cfg80211_attach_out;
5011 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005012
Arend van Spriel3eacf862012-10-22 13:55:30 -07005013 ifp->vif = vif;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005014 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005015
5016cfg80211_attach_out:
Arend van Spriel3eacf862012-10-22 13:55:30 -07005017 brcmf_free_vif(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005018 return NULL;
5019}
5020
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005021void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005022{
Arend van Spriel3eacf862012-10-22 13:55:30 -07005023 struct brcmf_cfg80211_vif *vif;
5024 struct brcmf_cfg80211_vif *tmp;
5025
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005026 wl_deinit_priv(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07005027 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
5028 brcmf_free_vif(vif);
5029 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005030}
5031
5032void
5033brcmf_cfg80211_event(struct net_device *ndev,
5034 const struct brcmf_event_msg *e, void *data)
5035{
5036 u32 event_type = be32_to_cpu(e->event_type);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005037 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005038
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005039 if (!brcmf_enq_event(cfg, event_type, e, data))
5040 schedule_work(&cfg->event_work);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005041}
5042
Arend van Spriel5b435de2011-10-05 13:19:03 +02005043static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
5044{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005045 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
5046 s32 err = 0;
5047
5048 WL_TRACE("Enter\n");
5049
5050 /* Setup event_msgs */
Arend van Sprielac24be62012-10-22 10:36:23 -07005051 err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
5052 eventmask, BRCMF_EVENTING_MASK_LEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005053 if (err) {
5054 WL_ERR("Get event_msgs error (%d)\n", err);
5055 goto dongle_eventmsg_out;
5056 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02005057
5058 setbit(eventmask, BRCMF_E_SET_SSID);
5059 setbit(eventmask, BRCMF_E_ROAM);
5060 setbit(eventmask, BRCMF_E_PRUNE);
5061 setbit(eventmask, BRCMF_E_AUTH);
5062 setbit(eventmask, BRCMF_E_REASSOC);
5063 setbit(eventmask, BRCMF_E_REASSOC_IND);
5064 setbit(eventmask, BRCMF_E_DEAUTH_IND);
5065 setbit(eventmask, BRCMF_E_DISASSOC_IND);
5066 setbit(eventmask, BRCMF_E_DISASSOC);
5067 setbit(eventmask, BRCMF_E_JOIN);
5068 setbit(eventmask, BRCMF_E_ASSOC_IND);
5069 setbit(eventmask, BRCMF_E_PSK_SUP);
5070 setbit(eventmask, BRCMF_E_LINK);
5071 setbit(eventmask, BRCMF_E_NDIS_LINK);
5072 setbit(eventmask, BRCMF_E_MIC_ERROR);
5073 setbit(eventmask, BRCMF_E_PMKID_CACHE);
5074 setbit(eventmask, BRCMF_E_TXFAIL);
5075 setbit(eventmask, BRCMF_E_JOIN_START);
5076 setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
Hante Meulemane756af52012-09-11 21:18:52 +02005077 setbit(eventmask, BRCMF_E_ESCAN_RESULT);
Arend van Spriele5806072012-09-19 22:21:08 +02005078 setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005079
Arend van Sprielac24be62012-10-22 10:36:23 -07005080 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
5081 eventmask, BRCMF_EVENTING_MASK_LEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005082 if (err) {
5083 WL_ERR("Set event_msgs error (%d)\n", err);
5084 goto dongle_eventmsg_out;
5085 }
5086
5087dongle_eventmsg_out:
5088 WL_TRACE("Exit\n");
5089 return err;
5090}
5091
5092static s32
5093brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
5094{
Arend van Sprielac24be62012-10-22 10:36:23 -07005095 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005096 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02005097 __le32 roamtrigger[2];
5098 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005099
5100 /*
5101 * Setup timeout if Beacons are lost and roam is
5102 * off to report link down
5103 */
5104 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07005105 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005106 if (err) {
5107 WL_ERR("bcn_timeout error (%d)\n", err);
5108 goto dongle_rom_out;
5109 }
5110 }
5111
5112 /*
5113 * Enable/Disable built-in roaming to allow supplicant
5114 * to take care of roaming
5115 */
5116 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07005117 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005118 if (err) {
5119 WL_ERR("roam_off error (%d)\n", err);
5120 goto dongle_rom_out;
5121 }
5122
Arend van Sprielf588bc02011-10-12 20:51:22 +02005123 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
5124 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005125 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005126 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005127 if (err) {
5128 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
5129 goto dongle_rom_out;
5130 }
5131
Arend van Sprielf588bc02011-10-12 20:51:22 +02005132 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
5133 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07005134 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005135 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005136 if (err) {
5137 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
5138 goto dongle_rom_out;
5139 }
5140
5141dongle_rom_out:
5142 return err;
5143}
5144
5145static s32
5146brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02005147 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005148{
Arend van Sprielac24be62012-10-22 10:36:23 -07005149 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005150 s32 err = 0;
5151
Arend van Sprielac24be62012-10-22 10:36:23 -07005152 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005153 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005154 if (err) {
5155 if (err == -EOPNOTSUPP)
5156 WL_INFO("Scan assoc time is not supported\n");
5157 else
5158 WL_ERR("Scan assoc time error (%d)\n", err);
5159 goto dongle_scantime_out;
5160 }
Arend van Sprielac24be62012-10-22 10:36:23 -07005161 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005162 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005163 if (err) {
5164 if (err == -EOPNOTSUPP)
5165 WL_INFO("Scan unassoc time is not supported\n");
5166 else
5167 WL_ERR("Scan unassoc time error (%d)\n", err);
5168 goto dongle_scantime_out;
5169 }
5170
Arend van Sprielac24be62012-10-22 10:36:23 -07005171 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005172 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005173 if (err) {
5174 if (err == -EOPNOTSUPP)
5175 WL_INFO("Scan passive time is not supported\n");
5176 else
5177 WL_ERR("Scan passive time error (%d)\n", err);
5178 goto dongle_scantime_out;
5179 }
5180
5181dongle_scantime_out:
5182 return err;
5183}
5184
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005185static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005186{
Arend van Sprielac24be62012-10-22 10:36:23 -07005187 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005188 struct wiphy *wiphy;
5189 s32 phy_list;
5190 s8 phy;
5191 s32 err = 0;
5192
Arend van Sprielac24be62012-10-22 10:36:23 -07005193 err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07005194 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005195 if (err) {
5196 WL_ERR("error (%d)\n", err);
5197 return err;
5198 }
5199
Hante Meuleman3ba81372012-09-19 22:21:13 +02005200 phy = ((char *)&phy_list)[0];
Arend van Spriel5b435de2011-10-05 13:19:03 +02005201 WL_INFO("%c phy\n", phy);
5202 if (phy == 'n' || phy == 'a') {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005203 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005204 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
5205 }
5206
5207 return err;
5208}
5209
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005210static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005211{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005212 return wl_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005213}
5214
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005215static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005216{
5217 struct net_device *ndev;
5218 struct wireless_dev *wdev;
5219 s32 power_mode;
5220 s32 err = 0;
5221
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005222 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005223 return err;
5224
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005225 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005226 wdev = ndev->ieee80211_ptr;
5227
5228 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
5229 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5230
5231 err = brcmf_dongle_eventmsg(ndev);
5232 if (err)
5233 goto default_conf_out;
5234
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005235 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Arend van Sprielac24be62012-10-22 10:36:23 -07005236 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
5237 power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005238 if (err)
5239 goto default_conf_out;
5240 WL_INFO("power save set to %s\n",
5241 (power_mode ? "enabled" : "disabled"));
5242
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005243 err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
Arend van Spriel5b435de2011-10-05 13:19:03 +02005244 WL_BEACON_TIMEOUT);
5245 if (err)
5246 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07005247 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
5248 NULL, NULL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005249 if (err && err != -EINPROGRESS)
5250 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005251 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005252 if (err)
5253 goto default_conf_out;
5254
5255 /* -EINPROGRESS: Call commit handler */
5256
5257default_conf_out:
5258
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005259 cfg->dongle_up = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02005260
5261 return err;
5262
5263}
5264
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005265static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005266{
Arend van Sprielc1179032012-10-22 13:55:33 -07005267 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02005268 s32 err = 0;
5269
Arend van Sprielc1179032012-10-22 13:55:33 -07005270 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005271
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005272 err = brcmf_config_dongle(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005273 if (err)
5274 return err;
5275
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005276 brcmf_invoke_iscan(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005277
5278 return err;
5279}
5280
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005281static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005282{
Arend van Sprielc1179032012-10-22 13:55:33 -07005283 struct net_device *ndev = cfg_to_ndev(cfg);
5284 struct brcmf_if *ifp = netdev_priv(ndev);
5285
Arend van Spriel5b435de2011-10-05 13:19:03 +02005286 /*
5287 * While going down, if associated with AP disassociate
5288 * from AP to save power
5289 */
Arend van Sprielc1179032012-10-22 13:55:33 -07005290 if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) ||
5291 test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) &&
Arend van Sprielce81e312012-10-22 13:55:37 -07005292 check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02005293 WL_INFO("Disassociating from AP");
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005294 brcmf_link_down(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005295
5296 /* Make sure WPA_Supplicant receives all the event
5297 generated due to DISASSOC call to the fw to keep
5298 the state fw and WPA_Supplicant state consistent
5299 */
5300 brcmf_delay(500);
5301 }
5302
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005303 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07005304 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005305
Arend van Spriel5b435de2011-10-05 13:19:03 +02005306 return 0;
5307}
5308
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005309s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005310{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005311 s32 err = 0;
5312
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005313 mutex_lock(&cfg->usr_sync);
5314 err = __brcmf_cfg80211_up(cfg);
5315 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005316
5317 return err;
5318}
5319
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005320s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02005321{
Arend van Spriel5b435de2011-10-05 13:19:03 +02005322 s32 err = 0;
5323
Arend van Spriel27a68fe2012-09-27 14:17:55 +02005324 mutex_lock(&cfg->usr_sync);
5325 err = __brcmf_cfg80211_down(cfg);
5326 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02005327
5328 return err;
5329}
5330