blob: d47b274018ba259d82e630045a7f9bc31d57ec61 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/etherdevice.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020021#include <net/cfg80211.h>
Arend van Sprielcbaa1772012-08-30 19:43:02 +020022#include <net/netlink.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020023
24#include <brcmu_utils.h>
25#include <defs.h>
26#include <brcmu_wifi.h>
27#include "dhd.h"
Arend van Spriel16886732012-12-05 15:26:04 +010028#include "dhd_dbg.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020029#include "wl_cfg80211.h"
Hante Meuleman81f5dcb2012-10-22 10:36:14 -070030#include "fwil.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020031
Arend van Spriele5806072012-09-19 22:21:08 +020032#define BRCMF_SCAN_IE_LEN_MAX 2048
33#define BRCMF_PNO_VERSION 2
34#define BRCMF_PNO_TIME 30
35#define BRCMF_PNO_REPEAT 4
36#define BRCMF_PNO_FREQ_EXPO_MAX 3
37#define BRCMF_PNO_MAX_PFN_COUNT 16
38#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
39#define BRCMF_PNO_HIDDEN_BIT 2
40#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
41#define BRCMF_PNO_SCAN_COMPLETE 1
42#define BRCMF_PNO_SCAN_INCOMPLETE 0
43
Arend van Spriel3eacf862012-10-22 13:55:30 -070044#define BRCMF_IFACE_MAX_CNT 2
45
Hante Meuleman1a873342012-09-27 14:17:54 +020046#define TLV_LEN_OFF 1 /* length offset */
Hante Meuleman04012892012-09-27 14:17:49 +020047#define TLV_HDR_LEN 2 /* header length */
Hante Meuleman1a873342012-09-27 14:17:54 +020048#define TLV_BODY_OFF 2 /* body offset */
49#define TLV_OUI_LEN 3 /* oui id length */
50#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
51#define WPA_OUI_TYPE 1
52#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
53#define WME_OUI_TYPE 2
54
55#define VS_IE_FIXED_HDR_LEN 6
56#define WPA_IE_VERSION_LEN 2
57#define WPA_IE_MIN_OUI_LEN 4
58#define WPA_IE_SUITE_COUNT_LEN 2
59
60#define WPA_CIPHER_NONE 0 /* None */
61#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
62#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
63#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
64#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
65
66#define RSN_AKM_NONE 0 /* None (IBSS) */
67#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
68#define RSN_AKM_PSK 2 /* Pre-shared Key */
69#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
70#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
71
72#define VNDR_IE_CMD_LEN 4 /* length of the set command
73 * string :"add", "del" (+ NUL)
74 */
75#define VNDR_IE_COUNT_OFFSET 4
76#define VNDR_IE_PKTFLAG_OFFSET 8
77#define VNDR_IE_VSIE_OFFSET 12
78#define VNDR_IE_HDR_SIZE 12
79#define VNDR_IE_BEACON_FLAG 0x1
80#define VNDR_IE_PRBRSP_FLAG 0x2
81#define MAX_VNDR_IE_NUMBER 5
82
83#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
84#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
Hante Meuleman04012892012-09-27 14:17:49 +020085
Arend van Spriel5b435de2011-10-05 13:19:03 +020086#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
87 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
88
Arend van Sprielce81e312012-10-22 13:55:37 -070089static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +020090{
Arend van Sprielc1179032012-10-22 13:55:33 -070091 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +010092 brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
93 vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +020094 return false;
95 }
96 return true;
97}
98
99#define CHAN2G(_channel, _freq, _flags) { \
100 .band = IEEE80211_BAND_2GHZ, \
101 .center_freq = (_freq), \
102 .hw_value = (_channel), \
103 .flags = (_flags), \
104 .max_antenna_gain = 0, \
105 .max_power = 30, \
106}
107
108#define CHAN5G(_channel, _flags) { \
109 .band = IEEE80211_BAND_5GHZ, \
110 .center_freq = 5000 + (5 * (_channel)), \
111 .hw_value = (_channel), \
112 .flags = (_flags), \
113 .max_antenna_gain = 0, \
114 .max_power = 30, \
115}
116
117#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
118#define RATETAB_ENT(_rateid, _flags) \
119 { \
120 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
121 .hw_value = (_rateid), \
122 .flags = (_flags), \
123 }
124
125static struct ieee80211_rate __wl_rates[] = {
126 RATETAB_ENT(BRCM_RATE_1M, 0),
127 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
128 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
129 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
130 RATETAB_ENT(BRCM_RATE_6M, 0),
131 RATETAB_ENT(BRCM_RATE_9M, 0),
132 RATETAB_ENT(BRCM_RATE_12M, 0),
133 RATETAB_ENT(BRCM_RATE_18M, 0),
134 RATETAB_ENT(BRCM_RATE_24M, 0),
135 RATETAB_ENT(BRCM_RATE_36M, 0),
136 RATETAB_ENT(BRCM_RATE_48M, 0),
137 RATETAB_ENT(BRCM_RATE_54M, 0),
138};
139
140#define wl_a_rates (__wl_rates + 4)
141#define wl_a_rates_size 8
142#define wl_g_rates (__wl_rates + 0)
143#define wl_g_rates_size 12
144
145static struct ieee80211_channel __wl_2ghz_channels[] = {
146 CHAN2G(1, 2412, 0),
147 CHAN2G(2, 2417, 0),
148 CHAN2G(3, 2422, 0),
149 CHAN2G(4, 2427, 0),
150 CHAN2G(5, 2432, 0),
151 CHAN2G(6, 2437, 0),
152 CHAN2G(7, 2442, 0),
153 CHAN2G(8, 2447, 0),
154 CHAN2G(9, 2452, 0),
155 CHAN2G(10, 2457, 0),
156 CHAN2G(11, 2462, 0),
157 CHAN2G(12, 2467, 0),
158 CHAN2G(13, 2472, 0),
159 CHAN2G(14, 2484, 0),
160};
161
162static struct ieee80211_channel __wl_5ghz_a_channels[] = {
163 CHAN5G(34, 0), CHAN5G(36, 0),
164 CHAN5G(38, 0), CHAN5G(40, 0),
165 CHAN5G(42, 0), CHAN5G(44, 0),
166 CHAN5G(46, 0), CHAN5G(48, 0),
167 CHAN5G(52, 0), CHAN5G(56, 0),
168 CHAN5G(60, 0), CHAN5G(64, 0),
169 CHAN5G(100, 0), CHAN5G(104, 0),
170 CHAN5G(108, 0), CHAN5G(112, 0),
171 CHAN5G(116, 0), CHAN5G(120, 0),
172 CHAN5G(124, 0), CHAN5G(128, 0),
173 CHAN5G(132, 0), CHAN5G(136, 0),
174 CHAN5G(140, 0), CHAN5G(149, 0),
175 CHAN5G(153, 0), CHAN5G(157, 0),
176 CHAN5G(161, 0), CHAN5G(165, 0),
177 CHAN5G(184, 0), CHAN5G(188, 0),
178 CHAN5G(192, 0), CHAN5G(196, 0),
179 CHAN5G(200, 0), CHAN5G(204, 0),
180 CHAN5G(208, 0), CHAN5G(212, 0),
181 CHAN5G(216, 0),
182};
183
184static struct ieee80211_channel __wl_5ghz_n_channels[] = {
185 CHAN5G(32, 0), CHAN5G(34, 0),
186 CHAN5G(36, 0), CHAN5G(38, 0),
187 CHAN5G(40, 0), CHAN5G(42, 0),
188 CHAN5G(44, 0), CHAN5G(46, 0),
189 CHAN5G(48, 0), CHAN5G(50, 0),
190 CHAN5G(52, 0), CHAN5G(54, 0),
191 CHAN5G(56, 0), CHAN5G(58, 0),
192 CHAN5G(60, 0), CHAN5G(62, 0),
193 CHAN5G(64, 0), CHAN5G(66, 0),
194 CHAN5G(68, 0), CHAN5G(70, 0),
195 CHAN5G(72, 0), CHAN5G(74, 0),
196 CHAN5G(76, 0), CHAN5G(78, 0),
197 CHAN5G(80, 0), CHAN5G(82, 0),
198 CHAN5G(84, 0), CHAN5G(86, 0),
199 CHAN5G(88, 0), CHAN5G(90, 0),
200 CHAN5G(92, 0), CHAN5G(94, 0),
201 CHAN5G(96, 0), CHAN5G(98, 0),
202 CHAN5G(100, 0), CHAN5G(102, 0),
203 CHAN5G(104, 0), CHAN5G(106, 0),
204 CHAN5G(108, 0), CHAN5G(110, 0),
205 CHAN5G(112, 0), CHAN5G(114, 0),
206 CHAN5G(116, 0), CHAN5G(118, 0),
207 CHAN5G(120, 0), CHAN5G(122, 0),
208 CHAN5G(124, 0), CHAN5G(126, 0),
209 CHAN5G(128, 0), CHAN5G(130, 0),
210 CHAN5G(132, 0), CHAN5G(134, 0),
211 CHAN5G(136, 0), CHAN5G(138, 0),
212 CHAN5G(140, 0), CHAN5G(142, 0),
213 CHAN5G(144, 0), CHAN5G(145, 0),
214 CHAN5G(146, 0), CHAN5G(147, 0),
215 CHAN5G(148, 0), CHAN5G(149, 0),
216 CHAN5G(150, 0), CHAN5G(151, 0),
217 CHAN5G(152, 0), CHAN5G(153, 0),
218 CHAN5G(154, 0), CHAN5G(155, 0),
219 CHAN5G(156, 0), CHAN5G(157, 0),
220 CHAN5G(158, 0), CHAN5G(159, 0),
221 CHAN5G(160, 0), CHAN5G(161, 0),
222 CHAN5G(162, 0), CHAN5G(163, 0),
223 CHAN5G(164, 0), CHAN5G(165, 0),
224 CHAN5G(166, 0), CHAN5G(168, 0),
225 CHAN5G(170, 0), CHAN5G(172, 0),
226 CHAN5G(174, 0), CHAN5G(176, 0),
227 CHAN5G(178, 0), CHAN5G(180, 0),
228 CHAN5G(182, 0), CHAN5G(184, 0),
229 CHAN5G(186, 0), CHAN5G(188, 0),
230 CHAN5G(190, 0), CHAN5G(192, 0),
231 CHAN5G(194, 0), CHAN5G(196, 0),
232 CHAN5G(198, 0), CHAN5G(200, 0),
233 CHAN5G(202, 0), CHAN5G(204, 0),
234 CHAN5G(206, 0), CHAN5G(208, 0),
235 CHAN5G(210, 0), CHAN5G(212, 0),
236 CHAN5G(214, 0), CHAN5G(216, 0),
237 CHAN5G(218, 0), CHAN5G(220, 0),
238 CHAN5G(222, 0), CHAN5G(224, 0),
239 CHAN5G(226, 0), CHAN5G(228, 0),
240};
241
242static struct ieee80211_supported_band __wl_band_2ghz = {
243 .band = IEEE80211_BAND_2GHZ,
244 .channels = __wl_2ghz_channels,
245 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
246 .bitrates = wl_g_rates,
247 .n_bitrates = wl_g_rates_size,
248};
249
250static struct ieee80211_supported_band __wl_band_5ghz_a = {
251 .band = IEEE80211_BAND_5GHZ,
252 .channels = __wl_5ghz_a_channels,
253 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
254 .bitrates = wl_a_rates,
255 .n_bitrates = wl_a_rates_size,
256};
257
258static struct ieee80211_supported_band __wl_band_5ghz_n = {
259 .band = IEEE80211_BAND_5GHZ,
260 .channels = __wl_5ghz_n_channels,
261 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
262 .bitrates = wl_a_rates,
263 .n_bitrates = wl_a_rates_size,
264};
265
266static const u32 __wl_cipher_suites[] = {
267 WLAN_CIPHER_SUITE_WEP40,
268 WLAN_CIPHER_SUITE_WEP104,
269 WLAN_CIPHER_SUITE_TKIP,
270 WLAN_CIPHER_SUITE_CCMP,
271 WLAN_CIPHER_SUITE_AES_CMAC,
272};
273
Alwin Beukersf8e4b412011-10-12 20:51:28 +0200274/* tag_ID/length/value_buffer tuple */
275struct brcmf_tlv {
276 u8 id;
277 u8 len;
278 u8 data[1];
279};
280
Hante Meuleman1a873342012-09-27 14:17:54 +0200281/* Vendor specific ie. id = 221, oui and type defines exact ie */
282struct brcmf_vs_tlv {
283 u8 id;
284 u8 len;
285 u8 oui[3];
286 u8 oui_type;
287};
288
289struct parsed_vndr_ie_info {
290 u8 *ie_ptr;
291 u32 ie_len; /* total length including id & length field */
292 struct brcmf_vs_tlv vndrie;
293};
294
295struct parsed_vndr_ies {
296 u32 count;
297 struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
298};
299
Alwin Beukersef6ac172011-10-12 20:51:26 +0200300/* Quarter dBm units to mW
301 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
302 * Table is offset so the last entry is largest mW value that fits in
303 * a u16.
304 */
305
306#define QDBM_OFFSET 153 /* Offset for first entry */
307#define QDBM_TABLE_LEN 40 /* Table size */
308
309/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
310 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
311 */
312#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
313
314/* Largest mW value that will round down to the last table entry,
315 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
316 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
317 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
318 */
319#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
320
321static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
322/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
323/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
324/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
325/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
326/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
327/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
328};
329
330static u16 brcmf_qdbm_to_mw(u8 qdbm)
331{
332 uint factor = 1;
333 int idx = qdbm - QDBM_OFFSET;
334
335 if (idx >= QDBM_TABLE_LEN)
336 /* clamp to max u16 mW value */
337 return 0xFFFF;
338
339 /* scale the qdBm index up to the range of the table 0-40
340 * where an offset of 40 qdBm equals a factor of 10 mW.
341 */
342 while (idx < 0) {
343 idx += 40;
344 factor *= 10;
345 }
346
347 /* return the mW value scaled down to the correct factor of 10,
348 * adding in factor/2 to get proper rounding.
349 */
350 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
351}
352
353static u8 brcmf_mw_to_qdbm(u16 mw)
354{
355 u8 qdbm;
356 int offset;
357 uint mw_uint = mw;
358 uint boundary;
359
360 /* handle boundary case */
361 if (mw_uint <= 1)
362 return 0;
363
364 offset = QDBM_OFFSET;
365
366 /* move mw into the range of the table */
367 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
368 mw_uint *= 10;
369 offset -= 40;
370 }
371
372 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
373 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
374 nqdBm_to_mW_map[qdbm]) / 2;
375 if (mw_uint < boundary)
376 break;
377 }
378
379 qdbm += (u8) offset;
380
381 return qdbm;
382}
383
Arend van Spriel6e186162012-10-22 10:36:22 -0700384static u16 channel_to_chanspec(struct ieee80211_channel *ch)
385{
386 u16 chanspec;
387
388 chanspec = ieee80211_frequency_to_channel(ch->center_freq);
389 chanspec &= WL_CHANSPEC_CHAN_MASK;
390
391 if (ch->band == IEEE80211_BAND_2GHZ)
392 chanspec |= WL_CHANSPEC_BAND_2G;
393 else
394 chanspec |= WL_CHANSPEC_BAND_5G;
395
Hante Meuleman17012612013-02-06 18:40:44 +0100396 chanspec |= WL_CHANSPEC_BW_20;
397 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
398
Arend van Spriel6e186162012-10-22 10:36:22 -0700399 return chanspec;
400}
401
Arend van Spriel5b435de2011-10-05 13:19:03 +0200402static void convert_key_from_CPU(struct brcmf_wsec_key *key,
403 struct brcmf_wsec_key_le *key_le)
404{
405 key_le->index = cpu_to_le32(key->index);
406 key_le->len = cpu_to_le32(key->len);
407 key_le->algo = cpu_to_le32(key->algo);
408 key_le->flags = cpu_to_le32(key->flags);
409 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
410 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
411 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
412 memcpy(key_le->data, key->data, sizeof(key->data));
413 memcpy(key_le->ea, key->ea, sizeof(key->ea));
414}
415
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200416static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700417send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200418{
419 int err;
420 struct brcmf_wsec_key_le key_le;
421
422 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200423
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700424 brcmf_netdev_wait_pend8021x(ndev);
425
Arend van Sprielac24be62012-10-22 10:36:23 -0700426 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700427 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200428
Arend van Spriel5b435de2011-10-05 13:19:03 +0200429 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100430 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200431 return err;
432}
433
434static s32
435brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
436 enum nl80211_iftype type, u32 *flags,
437 struct vif_params *params)
438{
Arend van Sprielc1179032012-10-22 13:55:33 -0700439 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100440 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200441 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200442 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200443 s32 err = 0;
444
Arend van Sprield96b8012012-12-05 15:26:02 +0100445 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200446
447 switch (type) {
448 case NL80211_IFTYPE_MONITOR:
449 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100450 brcmf_err("type (%d) : currently we do not support this type\n",
451 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200452 return -EOPNOTSUPP;
453 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100454 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200455 infra = 0;
456 break;
457 case NL80211_IFTYPE_STATION:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100458 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459 infra = 1;
460 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200461 case NL80211_IFTYPE_AP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100462 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200463 ap = 1;
464 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200465 default:
466 err = -EINVAL;
467 goto done;
468 }
469
Hante Meuleman1a873342012-09-27 14:17:54 +0200470 if (ap) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100471 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100472 brcmf_dbg(INFO, "IF Type = AP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200473 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100474 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200475 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100476 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200477 err = -EAGAIN;
478 goto done;
479 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100480 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
481 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200482 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200483 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200484
485done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100486 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200487
488 return err;
489}
490
Arend van Spriel5b435de2011-10-05 13:19:03 +0200491static void brcmf_set_mpc(struct net_device *ndev, int mpc)
492{
Arend van Sprielc1179032012-10-22 13:55:33 -0700493 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200494 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200495
Arend van Sprielce81e312012-10-22 13:55:37 -0700496 if (check_vif_up(ifp->vif)) {
Arend van Sprielc1179032012-10-22 13:55:33 -0700497 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200498 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100499 brcmf_err("fail to set mpc\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200500 return;
501 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100502 brcmf_dbg(INFO, "MPC : %d\n", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200503 }
504}
505
Hante Meulemane756af52012-09-11 21:18:52 +0200506static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
507 struct cfg80211_scan_request *request)
508{
509 u32 n_ssids;
510 u32 n_channels;
511 s32 i;
512 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200513 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200514 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200515 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200516
Arend van Sprielba40d162012-10-22 13:55:38 -0700517 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200518 params_le->bss_type = DOT11_BSSTYPE_ANY;
519 params_le->scan_type = 0;
520 params_le->channel_num = 0;
521 params_le->nprobes = cpu_to_le32(-1);
522 params_le->active_time = cpu_to_le32(-1);
523 params_le->passive_time = cpu_to_le32(-1);
524 params_le->home_time = cpu_to_le32(-1);
525 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
526
527 /* if request is null exit so it will be all channel broadcast scan */
528 if (!request)
529 return;
530
531 n_ssids = request->n_ssids;
532 n_channels = request->n_channels;
533 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100534 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
535 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200536 if (n_channels > 0) {
537 for (i = 0; i < n_channels; i++) {
Arend van Spriel6e186162012-10-22 10:36:22 -0700538 chanspec = channel_to_chanspec(request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100539 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
540 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200541 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200542 }
543 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100544 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200545 }
546 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100547 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200548 if (n_ssids > 0) {
549 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
550 n_channels * sizeof(u16);
551 offset = roundup(offset, sizeof(u32));
552 ptr = (char *)params_le + offset;
553 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200554 memset(&ssid_le, 0, sizeof(ssid_le));
555 ssid_le.SSID_len =
556 cpu_to_le32(request->ssids[i].ssid_len);
557 memcpy(ssid_le.SSID, request->ssids[i].ssid,
558 request->ssids[i].ssid_len);
559 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100560 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200561 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100562 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
563 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200564 memcpy(ptr, &ssid_le, sizeof(ssid_le));
565 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200566 }
567 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100568 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200569 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100570 brcmf_dbg(SCAN, "SSID %s len=%d\n",
571 params_le->ssid_le.SSID,
572 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200573 params_le->ssid_le.SSID_len =
574 cpu_to_le32(request->ssids->ssid_len);
575 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
576 request->ssids->ssid_len);
577 }
578 }
579 /* Adding mask to channel numbers */
580 params_le->channel_num =
581 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
582 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
583}
584
585static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200586brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
Hante Meulemane756af52012-09-11 21:18:52 +0200587 struct net_device *ndev,
588 bool aborted, bool fw_abort)
589{
590 struct brcmf_scan_params_le params_le;
591 struct cfg80211_scan_request *scan_request;
592 s32 err = 0;
593
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100594 brcmf_dbg(SCAN, "Enter\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200595
596 /* clear scan request, because the FW abort can cause a second call */
597 /* to this functon and might cause a double cfg80211_scan_done */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200598 scan_request = cfg->scan_request;
599 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200600
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200601 if (timer_pending(&cfg->escan_timeout))
602 del_timer_sync(&cfg->escan_timeout);
Hante Meulemane756af52012-09-11 21:18:52 +0200603
604 if (fw_abort) {
605 /* Do a scan abort to stop the driver's scan engine */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100606 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200607 memset(&params_le, 0, sizeof(params_le));
Arend van Sprielba40d162012-10-22 13:55:38 -0700608 memset(params_le.bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200609 params_le.bss_type = DOT11_BSSTYPE_ANY;
610 params_le.scan_type = 0;
611 params_le.channel_num = cpu_to_le32(1);
612 params_le.nprobes = cpu_to_le32(1);
613 params_le.active_time = cpu_to_le32(-1);
614 params_le.passive_time = cpu_to_le32(-1);
615 params_le.home_time = cpu_to_le32(-1);
616 /* Scan is aborted by setting channel_list[0] to -1 */
617 params_le.channel_list[0] = cpu_to_le16(-1);
618 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielac24be62012-10-22 10:36:23 -0700619 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
620 &params_le, sizeof(params_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200621 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100622 brcmf_err("Scan abort failed\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200623 }
Arend van Spriele5806072012-09-19 22:21:08 +0200624 /*
625 * e-scan can be initiated by scheduled scan
626 * which takes precedence.
627 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200628 if (cfg->sched_escan) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100629 brcmf_dbg(SCAN, "scheduled scan completed\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200630 cfg->sched_escan = false;
Arend van Spriele5806072012-09-19 22:21:08 +0200631 if (!aborted)
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200632 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriele5806072012-09-19 22:21:08 +0200633 brcmf_set_mpc(ndev, 1);
634 } else if (scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100635 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
636 aborted ? "Aborted" : "Done");
Hante Meulemane756af52012-09-11 21:18:52 +0200637 cfg80211_scan_done(scan_request, aborted);
638 brcmf_set_mpc(ndev, 1);
639 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700640 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100641 brcmf_err("Scan complete while device not scanning\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200642 return -EPERM;
643 }
644
645 return err;
646}
647
648static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200649brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
Hante Meulemane756af52012-09-11 21:18:52 +0200650 struct cfg80211_scan_request *request, u16 action)
651{
652 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
653 offsetof(struct brcmf_escan_params_le, params_le);
654 struct brcmf_escan_params_le *params;
655 s32 err = 0;
656
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100657 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200658
659 if (request != NULL) {
660 /* Allocate space for populating ssids in struct */
661 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
662
663 /* Allocate space for populating ssids in struct */
664 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
665 }
666
667 params = kzalloc(params_size, GFP_KERNEL);
668 if (!params) {
669 err = -ENOMEM;
670 goto exit;
671 }
672 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
673 brcmf_escan_prep(&params->params_le, request);
674 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
675 params->action = cpu_to_le16(action);
676 params->sync_id = cpu_to_le16(0x1234);
677
Arend van Sprielac24be62012-10-22 10:36:23 -0700678 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
679 params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200680 if (err) {
681 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100682 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200683 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100684 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200685 }
686
687 kfree(params);
688exit:
689 return err;
690}
691
692static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200693brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Hante Meulemane756af52012-09-11 21:18:52 +0200694 struct net_device *ndev, struct cfg80211_scan_request *request)
695{
696 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700697 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200698 struct brcmf_scan_results *results;
699
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100700 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200701 cfg->escan_info.ndev = ndev;
702 cfg->escan_info.wiphy = wiphy;
703 cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700704 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700705 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700706 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200707 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100708 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200709 return err;
710 }
711 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200712 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200713 results->version = 0;
714 results->count = 0;
715 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
716
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200717 err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200718 if (err)
719 brcmf_set_mpc(ndev, 1);
720 return err;
721}
722
723static s32
724brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
725 struct cfg80211_scan_request *request,
726 struct cfg80211_ssid *this_ssid)
727{
Arend van Sprielc1179032012-10-22 13:55:33 -0700728 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200729 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Hante Meulemane756af52012-09-11 21:18:52 +0200730 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800731 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700732 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200733 bool escan_req;
734 bool spec_scan;
735 s32 err;
736 u32 SSID_len;
737
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100738 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200739
Arend van Sprielc1179032012-10-22 13:55:33 -0700740 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100741 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200742 return -EAGAIN;
743 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700744 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100745 brcmf_err("Scanning being aborted: status (%lu)\n",
746 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200747 return -EAGAIN;
748 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700749 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100750 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200751 return -EAGAIN;
752 }
753
754 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200755 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200756 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
757
758 escan_req = false;
759 if (request) {
760 /* scan bss */
761 ssids = request->ssids;
762 escan_req = true;
763 } else {
764 /* scan in ibss */
765 /* we don't do escan in ibss */
766 ssids = this_ssid;
767 }
768
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200769 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700770 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200771 if (escan_req) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200772 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800773 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200774 goto scan_out;
775 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100776 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
777 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200778 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
779 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
780 sr->ssid_le.SSID_len = cpu_to_le32(0);
781 spec_scan = false;
782 if (SSID_len) {
783 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
784 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
785 spec_scan = true;
786 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100787 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200788
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700789 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700790 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700791 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200792 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100793 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200794 goto scan_out;
795 }
796 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700797 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700798 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200799 if (err) {
800 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100801 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
802 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200803 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100804 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200805
806 brcmf_set_mpc(ndev, 1);
807 goto scan_out;
808 }
809 }
810
811 return 0;
812
813scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700814 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200815 if (timer_pending(&cfg->escan_timeout))
816 del_timer_sync(&cfg->escan_timeout);
817 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200818 return err;
819}
820
Arend van Spriel5b435de2011-10-05 13:19:03 +0200821static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700822brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200823{
Johannes Bergfd014282012-06-18 19:17:03 +0200824 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200825 s32 err = 0;
826
Arend van Sprield96b8012012-12-05 15:26:02 +0100827 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200828
Arend van Sprielce81e312012-10-22 13:55:37 -0700829 if (!check_vif_up(container_of(request->wdev,
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700830 struct brcmf_cfg80211_vif, wdev)))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200831 return -EIO;
832
Hante Meulemanf07998952012-11-05 16:22:13 -0800833 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200834
Arend van Spriel5b435de2011-10-05 13:19:03 +0200835 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100836 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200837
Arend van Sprield96b8012012-12-05 15:26:02 +0100838 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200839 return err;
840}
841
842static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
843{
844 s32 err = 0;
845
Arend van Sprielac24be62012-10-22 10:36:23 -0700846 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
847 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200848 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100849 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200850
851 return err;
852}
853
854static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
855{
856 s32 err = 0;
857
Arend van Sprielac24be62012-10-22 10:36:23 -0700858 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
859 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200860 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100861 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200862
863 return err;
864}
865
866static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
867{
868 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -0800869 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200870
Arend van Sprielac24be62012-10-22 10:36:23 -0700871 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200872 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100873 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200874 return err;
875 }
876 return err;
877}
878
879static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
880{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200881 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
882 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700883 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200884 s32 err = 0;
885
Arend van Sprield96b8012012-12-05 15:26:02 +0100886 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -0700887 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200888 return -EIO;
889
890 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200891 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
892 cfg->conf->rts_threshold = wiphy->rts_threshold;
893 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200894 if (!err)
895 goto done;
896 }
897 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200898 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
899 cfg->conf->frag_threshold = wiphy->frag_threshold;
900 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200901 if (!err)
902 goto done;
903 }
904 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200905 && (cfg->conf->retry_long != wiphy->retry_long)) {
906 cfg->conf->retry_long = wiphy->retry_long;
907 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200908 if (!err)
909 goto done;
910 }
911 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200912 && (cfg->conf->retry_short != wiphy->retry_short)) {
913 cfg->conf->retry_short = wiphy->retry_short;
914 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200915 if (!err)
916 goto done;
917 }
918
919done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100920 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200921 return err;
922}
923
Arend van Spriel5b435de2011-10-05 13:19:03 +0200924static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
925{
926 memset(prof, 0, sizeof(*prof));
927}
928
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100929static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200930{
Arend van Spriel5b435de2011-10-05 13:19:03 +0200931 s32 err = 0;
932
Arend van Sprield96b8012012-12-05 15:26:02 +0100933 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200934
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100935 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100936 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100937 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -0700938 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200939 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100940 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100941 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200942 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100943 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +0100944 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200945}
946
947static s32
948brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
949 struct cfg80211_ibss_params *params)
950{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200951 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700952 struct brcmf_if *ifp = netdev_priv(ndev);
953 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200954 struct brcmf_join_params join_params;
955 size_t join_params_size = 0;
956 s32 err = 0;
957 s32 wsec = 0;
958 s32 bcnprd;
Hante Meuleman17012612013-02-06 18:40:44 +0100959 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200960
Arend van Sprield96b8012012-12-05 15:26:02 +0100961 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -0700962 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200963 return -EIO;
964
965 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +0100966 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200967 else {
Arend van Spriel16886732012-12-05 15:26:04 +0100968 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200969 return -EOPNOTSUPP;
970 }
971
Arend van Sprielc1179032012-10-22 13:55:33 -0700972 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200973
974 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +0100975 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200976 else
Arend van Spriel16886732012-12-05 15:26:04 +0100977 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200978
Johannes Berg683b6d32012-11-08 21:25:48 +0100979 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +0100980 brcmf_dbg(CONN, "channel: %d\n",
981 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200982 else
Arend van Spriel16886732012-12-05 15:26:04 +0100983 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200984
985 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +0100986 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200987 else
Arend van Spriel16886732012-12-05 15:26:04 +0100988 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200989
990 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +0100991 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200992 else
Arend van Spriel16886732012-12-05 15:26:04 +0100993 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200994
995 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +0100996 brcmf_dbg(CONN, "beacon interval: %d\n",
997 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200998 else
Arend van Spriel16886732012-12-05 15:26:04 +0100999 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001000
1001 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001002 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001003 else
Arend van Spriel16886732012-12-05 15:26:04 +01001004 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001005
1006 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001007 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001008 else
Arend van Spriel16886732012-12-05 15:26:04 +01001009 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001010
1011 /* Configure Privacy for starter */
1012 if (params->privacy)
1013 wsec |= WEP_ENABLED;
1014
Arend van Sprielc1179032012-10-22 13:55:33 -07001015 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001016 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001017 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001018 goto done;
1019 }
1020
1021 /* Configure Beacon Interval for starter */
1022 if (params->beacon_interval)
1023 bcnprd = params->beacon_interval;
1024 else
1025 bcnprd = 100;
1026
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001027 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001028 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001029 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001030 goto done;
1031 }
1032
1033 /* Configure required join parameter */
1034 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1035
1036 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001037 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1038 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1039 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1040 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001041 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001042
1043 /* BSSID */
1044 if (params->bssid) {
1045 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1046 join_params_size = sizeof(join_params.ssid_le) +
1047 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001048 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001049 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001050 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001051 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001052 }
1053
Arend van Spriel5b435de2011-10-05 13:19:03 +02001054 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001055 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001056 u32 target_channel;
1057
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001058 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001059 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001060 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001061 if (params->channel_fixed) {
1062 /* adding chanspec */
Hante Meuleman17012612013-02-06 18:40:44 +01001063 chanspec = channel_to_chanspec(params->chandef.chan);
1064 join_params.params_le.chanspec_list[0] =
1065 cpu_to_le16(chanspec);
1066 join_params.params_le.chanspec_num = cpu_to_le32(1);
1067 join_params_size += sizeof(join_params.params_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001068 }
1069
1070 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001071 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001072 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001073 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001074 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001075 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001076 goto done;
1077 }
1078 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001079 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001080
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001081 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001082
1083
Arend van Sprielc1179032012-10-22 13:55:33 -07001084 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001085 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001086 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001087 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001088 goto done;
1089 }
1090
1091done:
1092 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001093 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001094 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001095 return err;
1096}
1097
1098static s32
1099brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1100{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001101 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001102 s32 err = 0;
1103
Arend van Sprield96b8012012-12-05 15:26:02 +01001104 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001105 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001106 return -EIO;
1107
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001108 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001109
Arend van Sprield96b8012012-12-05 15:26:02 +01001110 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001111
1112 return err;
1113}
1114
1115static s32 brcmf_set_wpa_version(struct net_device *ndev,
1116 struct cfg80211_connect_params *sme)
1117{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001118 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001119 struct brcmf_cfg80211_security *sec;
1120 s32 val = 0;
1121 s32 err = 0;
1122
1123 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1124 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1125 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1126 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1127 else
1128 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001129 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001130 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001131 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001132 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001133 return err;
1134 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001135 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001136 sec->wpa_versions = sme->crypto.wpa_versions;
1137 return err;
1138}
1139
1140static s32 brcmf_set_auth_type(struct net_device *ndev,
1141 struct cfg80211_connect_params *sme)
1142{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001143 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001144 struct brcmf_cfg80211_security *sec;
1145 s32 val = 0;
1146 s32 err = 0;
1147
1148 switch (sme->auth_type) {
1149 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1150 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001151 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001152 break;
1153 case NL80211_AUTHTYPE_SHARED_KEY:
1154 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001155 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001156 break;
1157 case NL80211_AUTHTYPE_AUTOMATIC:
1158 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001159 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001160 break;
1161 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001162 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001163 default:
1164 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001165 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001166 break;
1167 }
1168
Arend van Sprielac24be62012-10-22 10:36:23 -07001169 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001171 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001172 return err;
1173 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001174 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001175 sec->auth_type = sme->auth_type;
1176 return err;
1177}
1178
1179static s32
1180brcmf_set_set_cipher(struct net_device *ndev,
1181 struct cfg80211_connect_params *sme)
1182{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001183 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001184 struct brcmf_cfg80211_security *sec;
1185 s32 pval = 0;
1186 s32 gval = 0;
1187 s32 err = 0;
1188
1189 if (sme->crypto.n_ciphers_pairwise) {
1190 switch (sme->crypto.ciphers_pairwise[0]) {
1191 case WLAN_CIPHER_SUITE_WEP40:
1192 case WLAN_CIPHER_SUITE_WEP104:
1193 pval = WEP_ENABLED;
1194 break;
1195 case WLAN_CIPHER_SUITE_TKIP:
1196 pval = TKIP_ENABLED;
1197 break;
1198 case WLAN_CIPHER_SUITE_CCMP:
1199 pval = AES_ENABLED;
1200 break;
1201 case WLAN_CIPHER_SUITE_AES_CMAC:
1202 pval = AES_ENABLED;
1203 break;
1204 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001205 brcmf_err("invalid cipher pairwise (%d)\n",
1206 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001207 return -EINVAL;
1208 }
1209 }
1210 if (sme->crypto.cipher_group) {
1211 switch (sme->crypto.cipher_group) {
1212 case WLAN_CIPHER_SUITE_WEP40:
1213 case WLAN_CIPHER_SUITE_WEP104:
1214 gval = WEP_ENABLED;
1215 break;
1216 case WLAN_CIPHER_SUITE_TKIP:
1217 gval = TKIP_ENABLED;
1218 break;
1219 case WLAN_CIPHER_SUITE_CCMP:
1220 gval = AES_ENABLED;
1221 break;
1222 case WLAN_CIPHER_SUITE_AES_CMAC:
1223 gval = AES_ENABLED;
1224 break;
1225 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001226 brcmf_err("invalid cipher group (%d)\n",
1227 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001228 return -EINVAL;
1229 }
1230 }
1231
Arend van Spriel16886732012-12-05 15:26:04 +01001232 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Arend van Sprielac24be62012-10-22 10:36:23 -07001233 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001234 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001235 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001236 return err;
1237 }
1238
Arend van Spriel06bb1232012-09-27 14:17:56 +02001239 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001240 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1241 sec->cipher_group = sme->crypto.cipher_group;
1242
1243 return err;
1244}
1245
1246static s32
1247brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1248{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001249 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250 struct brcmf_cfg80211_security *sec;
1251 s32 val = 0;
1252 s32 err = 0;
1253
1254 if (sme->crypto.n_akm_suites) {
Arend van Sprielac24be62012-10-22 10:36:23 -07001255 err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
1256 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001257 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001258 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001259 return err;
1260 }
1261 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1262 switch (sme->crypto.akm_suites[0]) {
1263 case WLAN_AKM_SUITE_8021X:
1264 val = WPA_AUTH_UNSPECIFIED;
1265 break;
1266 case WLAN_AKM_SUITE_PSK:
1267 val = WPA_AUTH_PSK;
1268 break;
1269 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001270 brcmf_err("invalid cipher group (%d)\n",
1271 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001272 return -EINVAL;
1273 }
1274 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1275 switch (sme->crypto.akm_suites[0]) {
1276 case WLAN_AKM_SUITE_8021X:
1277 val = WPA2_AUTH_UNSPECIFIED;
1278 break;
1279 case WLAN_AKM_SUITE_PSK:
1280 val = WPA2_AUTH_PSK;
1281 break;
1282 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001283 brcmf_err("invalid cipher group (%d)\n",
1284 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 return -EINVAL;
1286 }
1287 }
1288
Arend van Spriel16886732012-12-05 15:26:04 +01001289 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001290 err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
1291 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001292 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001293 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001294 return err;
1295 }
1296 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001297 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001298 sec->wpa_auth = sme->crypto.akm_suites[0];
1299
1300 return err;
1301}
1302
1303static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001304brcmf_set_sharedkey(struct net_device *ndev,
1305 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001306{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001307 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001308 struct brcmf_cfg80211_security *sec;
1309 struct brcmf_wsec_key key;
1310 s32 val;
1311 s32 err = 0;
1312
Arend van Spriel16886732012-12-05 15:26:04 +01001313 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001314
Roland Vossena718e2f2011-10-12 20:51:24 +02001315 if (sme->key_len == 0)
1316 return 0;
1317
Arend van Spriel06bb1232012-09-27 14:17:56 +02001318 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001319 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1320 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001321
1322 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1323 return 0;
1324
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001325 if (!(sec->cipher_pairwise &
1326 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1327 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001328
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001329 memset(&key, 0, sizeof(key));
1330 key.len = (u32) sme->key_len;
1331 key.index = (u32) sme->key_idx;
1332 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001333 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001334 return -EINVAL;
1335 }
1336 memcpy(key.data, sme->key, key.len);
1337 key.flags = BRCMF_PRIMARY_KEY;
1338 switch (sec->cipher_pairwise) {
1339 case WLAN_CIPHER_SUITE_WEP40:
1340 key.algo = CRYPTO_ALGO_WEP1;
1341 break;
1342 case WLAN_CIPHER_SUITE_WEP104:
1343 key.algo = CRYPTO_ALGO_WEP128;
1344 break;
1345 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001346 brcmf_err("Invalid algorithm (%d)\n",
1347 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001348 return -EINVAL;
1349 }
1350 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001351 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1352 key.len, key.index, key.algo);
1353 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001354 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001355 if (err)
1356 return err;
1357
1358 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001359 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001360 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001361 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001362 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001363 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001364 }
1365 return err;
1366}
1367
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001368static
1369enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
1370 enum nl80211_auth_type type)
1371{
1372 u32 ci;
1373 if (type == NL80211_AUTHTYPE_AUTOMATIC) {
1374 /* shift to ignore chip revision */
1375 ci = brcmf_get_chip_info(ifp) >> 4;
1376 switch (ci) {
1377 case 43236:
1378 brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
1379 return NL80211_AUTHTYPE_OPEN_SYSTEM;
1380 default:
1381 break;
1382 }
1383 }
1384 return type;
1385}
1386
Arend van Spriel5b435de2011-10-05 13:19:03 +02001387static s32
1388brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001389 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001390{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001391 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001392 struct brcmf_if *ifp = netdev_priv(ndev);
1393 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001394 struct ieee80211_channel *chan = sme->channel;
1395 struct brcmf_join_params join_params;
1396 size_t join_params_size;
1397 struct brcmf_ssid ssid;
Hante Meuleman17012612013-02-06 18:40:44 +01001398 u16 chanspec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001399
1400 s32 err = 0;
1401
Arend van Sprield96b8012012-12-05 15:26:02 +01001402 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001403 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001404 return -EIO;
1405
1406 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001407 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 return -EOPNOTSUPP;
1409 }
1410
Arend van Sprielc1179032012-10-22 13:55:33 -07001411 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001412
1413 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001414 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001415 ieee80211_frequency_to_channel(chan->center_freq);
Hante Meuleman17012612013-02-06 18:40:44 +01001416 chanspec = channel_to_chanspec(chan);
1417 brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
1418 cfg->channel, chan->center_freq, chanspec);
1419 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001420 cfg->channel = 0;
Hante Meuleman17012612013-02-06 18:40:44 +01001421 chanspec = 0;
1422 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001423
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001424 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001425
1426 err = brcmf_set_wpa_version(ndev, sme);
1427 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001428 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001429 goto done;
1430 }
1431
Arend van Sprielcbb1ec92013-02-06 18:40:47 +01001432 sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001433 err = brcmf_set_auth_type(ndev, sme);
1434 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001435 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436 goto done;
1437 }
1438
1439 err = brcmf_set_set_cipher(ndev, sme);
1440 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001441 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001442 goto done;
1443 }
1444
1445 err = brcmf_set_key_mgmt(ndev, sme);
1446 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001447 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001448 goto done;
1449 }
1450
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001451 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001453 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001454 goto done;
1455 }
1456
1457 memset(&join_params, 0, sizeof(join_params));
1458 join_params_size = sizeof(join_params.ssid_le);
1459
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001460 profile->ssid.SSID_len = min_t(u32,
1461 sizeof(ssid.SSID), (u32)sme->ssid_len);
1462 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
1463 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1464 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001465
Arend van Sprielba40d162012-10-22 13:55:38 -07001466 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001467
1468 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
Arend van Spriel16886732012-12-05 15:26:04 +01001469 brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
1470 ssid.SSID, ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001471
Hante Meuleman17012612013-02-06 18:40:44 +01001472 if (cfg->channel) {
1473 join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
1474 join_params.params_le.chanspec_num = cpu_to_le32(1);
1475 join_params_size += sizeof(join_params.params_le);
1476 }
Arend van Sprielc1179032012-10-22 13:55:33 -07001477 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001478 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001479 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001480 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001481
1482done:
1483 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001484 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001485 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001486 return err;
1487}
1488
1489static s32
1490brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1491 u16 reason_code)
1492{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001493 struct brcmf_if *ifp = netdev_priv(ndev);
1494 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001495 struct brcmf_scb_val_le scbval;
1496 s32 err = 0;
1497
Arend van Sprield96b8012012-12-05 15:26:02 +01001498 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001499 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001500 return -EIO;
1501
Arend van Sprielc1179032012-10-22 13:55:33 -07001502 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001503
Arend van Spriel06bb1232012-09-27 14:17:56 +02001504 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001505 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001506 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001507 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001508 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001509 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001510
Arend van Sprield96b8012012-12-05 15:26:02 +01001511 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512 return err;
1513}
1514
1515static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001516brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001517 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001518{
1519
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001520 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001521 struct net_device *ndev = cfg_to_ndev(cfg);
1522 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001523 u16 txpwrmw;
1524 s32 err = 0;
1525 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001526 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001527
Arend van Sprield96b8012012-12-05 15:26:02 +01001528 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001529 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001530 return -EIO;
1531
1532 switch (type) {
1533 case NL80211_TX_POWER_AUTOMATIC:
1534 break;
1535 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001536 case NL80211_TX_POWER_FIXED:
1537 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001538 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001539 err = -EINVAL;
1540 goto done;
1541 }
1542 break;
1543 }
1544 /* Make sure radio is off or on as far as software is concerned */
1545 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001546 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001547 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001548 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001549
1550 if (dbm > 0xffff)
1551 txpwrmw = 0xffff;
1552 else
1553 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001554 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1555 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001556 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001557 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001558 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001559
1560done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001561 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001562 return err;
1563}
1564
Johannes Bergc8442112012-10-24 10:17:18 +02001565static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1566 struct wireless_dev *wdev,
1567 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001568{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001569 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001570 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001571 s32 txpwrdbm;
1572 u8 result;
1573 s32 err = 0;
1574
Arend van Sprield96b8012012-12-05 15:26:02 +01001575 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001576 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001577 return -EIO;
1578
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001579 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001580 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001581 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001582 goto done;
1583 }
1584
1585 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001586 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001587
1588done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001589 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001590 return err;
1591}
1592
1593static s32
1594brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1595 u8 key_idx, bool unicast, bool multicast)
1596{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001597 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001598 u32 index;
1599 u32 wsec;
1600 s32 err = 0;
1601
Arend van Sprield96b8012012-12-05 15:26:02 +01001602 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001603 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001604 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001605 return -EIO;
1606
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001607 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001608 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001609 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001610 goto done;
1611 }
1612
1613 if (wsec & WEP_ENABLED) {
1614 /* Just select a new current key */
1615 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001616 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001617 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001618 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001619 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001620 }
1621done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001622 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001623 return err;
1624}
1625
1626static s32
1627brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1628 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1629{
1630 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001631 s32 err = 0;
1632
1633 memset(&key, 0, sizeof(key));
1634 key.index = (u32) key_idx;
1635 /* Instead of bcast for ea address for default wep keys,
1636 driver needs it to be Null */
1637 if (!is_multicast_ether_addr(mac_addr))
1638 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1639 key.len = (u32) params->key_len;
1640 /* check for key index change */
1641 if (key.len == 0) {
1642 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001643 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001644 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001645 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001646 } else {
1647 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001648 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001649 return -EINVAL;
1650 }
1651
Arend van Spriel16886732012-12-05 15:26:04 +01001652 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001653 memcpy(key.data, params->key, key.len);
1654
1655 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1656 u8 keybuf[8];
1657 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1658 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1659 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1660 }
1661
1662 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1663 if (params->seq && params->seq_len == 6) {
1664 /* rx iv */
1665 u8 *ivptr;
1666 ivptr = (u8 *) params->seq;
1667 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1668 (ivptr[3] << 8) | ivptr[2];
1669 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1670 key.iv_initialized = true;
1671 }
1672
1673 switch (params->cipher) {
1674 case WLAN_CIPHER_SUITE_WEP40:
1675 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001676 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001677 break;
1678 case WLAN_CIPHER_SUITE_WEP104:
1679 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001680 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001681 break;
1682 case WLAN_CIPHER_SUITE_TKIP:
1683 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001684 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001685 break;
1686 case WLAN_CIPHER_SUITE_AES_CMAC:
1687 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001688 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001689 break;
1690 case WLAN_CIPHER_SUITE_CCMP:
1691 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001692 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001693 break;
1694 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001695 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001696 return -EINVAL;
1697 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001698 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001699 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001700 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001701 }
1702 return err;
1703}
1704
1705static s32
1706brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1707 u8 key_idx, bool pairwise, const u8 *mac_addr,
1708 struct key_params *params)
1709{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001710 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001711 struct brcmf_wsec_key key;
1712 s32 val;
1713 s32 wsec;
1714 s32 err = 0;
1715 u8 keybuf[8];
1716
Arend van Sprield96b8012012-12-05 15:26:02 +01001717 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001718 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001719 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001720 return -EIO;
1721
1722 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001723 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001724 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1725 }
1726 memset(&key, 0, sizeof(key));
1727
1728 key.len = (u32) params->key_len;
1729 key.index = (u32) key_idx;
1730
1731 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001732 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001733 err = -EINVAL;
1734 goto done;
1735 }
1736 memcpy(key.data, params->key, key.len);
1737
1738 key.flags = BRCMF_PRIMARY_KEY;
1739 switch (params->cipher) {
1740 case WLAN_CIPHER_SUITE_WEP40:
1741 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001742 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001743 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001744 break;
1745 case WLAN_CIPHER_SUITE_WEP104:
1746 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001747 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001748 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001749 break;
1750 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001751 if (ifp->vif->mode != WL_MODE_AP) {
Arend van Spriel16886732012-12-05 15:26:04 +01001752 brcmf_dbg(CONN, "Swapping key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02001753 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1754 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1755 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1756 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001757 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001758 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001759 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001760 break;
1761 case WLAN_CIPHER_SUITE_AES_CMAC:
1762 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001763 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001764 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001765 break;
1766 case WLAN_CIPHER_SUITE_CCMP:
1767 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001768 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001769 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770 break;
1771 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001772 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001773 err = -EINVAL;
1774 goto done;
1775 }
1776
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001777 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001778 if (err)
1779 goto done;
1780
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001781 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001782 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001783 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001784 goto done;
1785 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001786 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001787 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001788 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001789 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001790 goto done;
1791 }
1792
Arend van Spriel5b435de2011-10-05 13:19:03 +02001793done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001794 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001795 return err;
1796}
1797
1798static s32
1799brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1800 u8 key_idx, bool pairwise, const u8 *mac_addr)
1801{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001802 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001803 struct brcmf_wsec_key key;
1804 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001805
Arend van Sprield96b8012012-12-05 15:26:02 +01001806 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001807 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001808 return -EIO;
1809
Hante Meuleman256c3742012-11-05 16:22:28 -08001810 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
1811 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01001812 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08001813 return -EINVAL;
1814 }
1815
Arend van Spriel5b435de2011-10-05 13:19:03 +02001816 memset(&key, 0, sizeof(key));
1817
1818 key.index = (u32) key_idx;
1819 key.flags = BRCMF_PRIMARY_KEY;
1820 key.algo = CRYPTO_ALGO_OFF;
1821
Arend van Spriel16886732012-12-05 15:26:04 +01001822 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001823
1824 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001825 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001826
Arend van Sprield96b8012012-12-05 15:26:02 +01001827 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001828 return err;
1829}
1830
1831static s32
1832brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1833 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
1834 void (*callback) (void *cookie, struct key_params * params))
1835{
1836 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001837 struct brcmf_if *ifp = netdev_priv(ndev);
1838 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001839 struct brcmf_cfg80211_security *sec;
1840 s32 wsec;
1841 s32 err = 0;
1842
Arend van Sprield96b8012012-12-05 15:26:02 +01001843 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001844 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001845 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001846 return -EIO;
1847
1848 memset(&params, 0, sizeof(params));
1849
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001850 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001851 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001852 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001853 /* Ignore this error, may happen during DISASSOC */
1854 err = -EAGAIN;
1855 goto done;
1856 }
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001857 switch (wsec & ~SES_OW_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001858 case WEP_ENABLED:
Arend van Spriel06bb1232012-09-27 14:17:56 +02001859 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001860 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1861 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01001862 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001863 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1864 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01001865 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001866 }
1867 break;
1868 case TKIP_ENABLED:
1869 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001870 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001871 break;
1872 case AES_ENABLED:
1873 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01001874 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001875 break;
1876 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001877 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001878 err = -EINVAL;
1879 goto done;
1880 }
1881 callback(cookie, &params);
1882
1883done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001884 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001885 return err;
1886}
1887
1888static s32
1889brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
1890 struct net_device *ndev, u8 key_idx)
1891{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001892 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001893
1894 return -EOPNOTSUPP;
1895}
1896
1897static s32
1898brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02001899 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001900{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001901 struct brcmf_if *ifp = netdev_priv(ndev);
1902 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001903 struct brcmf_scb_val_le scb_val;
1904 int rssi;
1905 s32 rate;
1906 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02001907 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001908 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001909
Arend van Sprield96b8012012-12-05 15:26:02 +01001910 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07001911 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001912 return -EIO;
1913
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001914 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001915 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001916 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07001917 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001918 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02001919 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001920 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001921 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02001922 }
Hante Meuleman1a873342012-09-27 14:17:54 +02001923 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001924 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
1925 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001926 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001927 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02001928 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001929 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
1930 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001931 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001932 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001933 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
1934 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02001935 err = -ENOENT;
1936 goto done;
1937 }
1938 /* Report the current tx rate */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001939 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02001940 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001941 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001942 goto done;
1943 } else {
1944 sinfo->filled |= STATION_INFO_TX_BITRATE;
1945 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01001946 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02001947 }
1948
Arend van Sprielc1179032012-10-22 13:55:33 -07001949 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
1950 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001951 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07001952 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
1953 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02001954 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001955 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001956 goto done;
1957 } else {
1958 rssi = le32_to_cpu(scb_val.val);
1959 sinfo->filled |= STATION_INFO_SIGNAL;
1960 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01001961 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02001962 }
1963 }
1964 } else
1965 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001966done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001967 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001968 return err;
1969}
1970
1971static s32
1972brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
1973 bool enabled, s32 timeout)
1974{
1975 s32 pm;
1976 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001977 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07001978 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001979
Arend van Sprield96b8012012-12-05 15:26:02 +01001980 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001981
1982 /*
1983 * Powersave enable/disable request is coming from the
1984 * cfg80211 even before the interface is up. In that
1985 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001986 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02001987 * FW later while initializing the dongle
1988 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001989 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07001990 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001991
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001992 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001993 goto done;
1994 }
1995
1996 pm = enabled ? PM_FAST : PM_OFF;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001997 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001998
Arend van Sprielc1179032012-10-22 13:55:33 -07001999 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002000 if (err) {
2001 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002002 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002003 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002004 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002005 }
2006done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002007 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002008 return err;
2009}
2010
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002011static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002012 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002013{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002014 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002015 struct ieee80211_channel *notify_channel;
2016 struct cfg80211_bss *bss;
2017 struct ieee80211_supported_band *band;
2018 s32 err = 0;
2019 u16 channel;
2020 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002021 u16 notify_capability;
2022 u16 notify_interval;
2023 u8 *notify_ie;
2024 size_t notify_ielen;
2025 s32 notify_signal;
2026
2027 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002028 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002029 return 0;
2030 }
2031
2032 channel = bi->ctl_ch ? bi->ctl_ch :
2033 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2034
2035 if (channel <= CH_MAX_2G_CHANNEL)
2036 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2037 else
2038 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2039
2040 freq = ieee80211_channel_to_frequency(channel, band->band);
2041 notify_channel = ieee80211_get_channel(wiphy, freq);
2042
Arend van Spriel5b435de2011-10-05 13:19:03 +02002043 notify_capability = le16_to_cpu(bi->capability);
2044 notify_interval = le16_to_cpu(bi->beacon_period);
2045 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2046 notify_ielen = le32_to_cpu(bi->ie_length);
2047 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2048
Arend van Spriel16886732012-12-05 15:26:04 +01002049 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2050 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2051 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2052 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2053 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002054
2055 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002056 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002057 notify_ielen, notify_signal, GFP_KERNEL);
2058
Franky Line78946e2011-11-10 20:30:34 +01002059 if (!bss)
2060 return -ENOMEM;
2061
2062 cfg80211_put_bss(bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002063
2064 return err;
2065}
2066
Roland Vossen6f09be02011-10-18 14:03:02 +02002067static struct brcmf_bss_info_le *
2068next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2069{
2070 if (bss == NULL)
2071 return list->bss_info_le;
2072 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2073 le32_to_cpu(bss->length));
2074}
2075
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002076static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002077{
2078 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002079 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 s32 err = 0;
2081 int i;
2082
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002083 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002084 if (bss_list->count != 0 &&
2085 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002086 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2087 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002088 return -EOPNOTSUPP;
2089 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002090 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002091 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002092 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002093 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002094 if (err)
2095 break;
2096 }
2097 return err;
2098}
2099
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002100static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002101 struct net_device *ndev, const u8 *bssid)
2102{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002103 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002104 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002105 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002106 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002107 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002108 u8 *buf = NULL;
2109 s32 err = 0;
2110 u16 channel;
2111 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002112 u16 notify_capability;
2113 u16 notify_interval;
2114 u8 *notify_ie;
2115 size_t notify_ielen;
2116 s32 notify_signal;
2117
Arend van Sprield96b8012012-12-05 15:26:02 +01002118 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002119
2120 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2121 if (buf == NULL) {
2122 err = -ENOMEM;
2123 goto CleanUp;
2124 }
2125
2126 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2127
Arend van Sprielac24be62012-10-22 10:36:23 -07002128 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2129 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002130 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002131 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002132 goto CleanUp;
2133 }
2134
Roland Vossend34bf642011-10-18 14:03:01 +02002135 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002136
2137 channel = bi->ctl_ch ? bi->ctl_ch :
2138 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2139
2140 if (channel <= CH_MAX_2G_CHANNEL)
2141 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2142 else
2143 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2144
2145 freq = ieee80211_channel_to_frequency(channel, band->band);
2146 notify_channel = ieee80211_get_channel(wiphy, freq);
2147
Arend van Spriel5b435de2011-10-05 13:19:03 +02002148 notify_capability = le16_to_cpu(bi->capability);
2149 notify_interval = le16_to_cpu(bi->beacon_period);
2150 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2151 notify_ielen = le32_to_cpu(bi->ie_length);
2152 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2153
Arend van Spriel16886732012-12-05 15:26:04 +01002154 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2155 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2156 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2157 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002158
Franky Line78946e2011-11-10 20:30:34 +01002159 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002160 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002161 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2162
Franky Line78946e2011-11-10 20:30:34 +01002163 if (!bss) {
2164 err = -ENOMEM;
2165 goto CleanUp;
2166 }
2167
2168 cfg80211_put_bss(bss);
2169
Arend van Spriel5b435de2011-10-05 13:19:03 +02002170CleanUp:
2171
2172 kfree(buf);
2173
Arend van Sprield96b8012012-12-05 15:26:02 +01002174 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002175
2176 return err;
2177}
2178
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002179static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002180{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002181 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002182}
2183
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002184/*
2185 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2186 * triples, returning a pointer to the substring whose first element
2187 * matches tag
2188 */
2189static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
2190{
2191 struct brcmf_tlv *elt;
2192 int totlen;
2193
2194 elt = (struct brcmf_tlv *) buf;
2195 totlen = buflen;
2196
2197 /* find tagged parameter */
Hante Meuleman04012892012-09-27 14:17:49 +02002198 while (totlen >= TLV_HDR_LEN) {
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002199 int len = elt->len;
2200
2201 /* validate remaining totlen */
Hante Meuleman04012892012-09-27 14:17:49 +02002202 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002203 return elt;
2204
Hante Meuleman04012892012-09-27 14:17:49 +02002205 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
2206 totlen -= (len + TLV_HDR_LEN);
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002207 }
2208
2209 return NULL;
2210}
2211
Hante Meuleman1a873342012-09-27 14:17:54 +02002212/* Is any of the tlvs the expected entry? If
2213 * not update the tlvs buffer pointer/length.
2214 */
2215static bool
2216brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
2217 u8 *oui, u32 oui_len, u8 type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002218{
Hante Meuleman1a873342012-09-27 14:17:54 +02002219 /* If the contents match the OUI and the type */
2220 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
2221 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
2222 type == ie[TLV_BODY_OFF + oui_len]) {
2223 return true;
2224 }
2225
2226 if (tlvs == NULL)
2227 return false;
2228 /* point to the next ie */
2229 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
2230 /* calculate the length of the rest of the buffer */
2231 *tlvs_len -= (int)(ie - *tlvs);
2232 /* update the pointer to the start of the buffer */
2233 *tlvs = ie;
2234
2235 return false;
2236}
2237
Franky Lin3cb91f52012-10-10 11:13:08 -07002238static struct brcmf_vs_tlv *
Hante Meuleman1a873342012-09-27 14:17:54 +02002239brcmf_find_wpaie(u8 *parse, u32 len)
2240{
2241 struct brcmf_tlv *ie;
2242
Arend van Spriel04b23122012-10-12 12:28:14 +02002243 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002244 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
2245 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
2246 return (struct brcmf_vs_tlv *)ie;
2247 }
2248 return NULL;
2249}
2250
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002251static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002252{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07002253 struct net_device *ndev = cfg_to_ndev(cfg);
2254 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
2255 struct brcmf_if *ifp = netdev_priv(ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002256 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002257 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002258 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002259 u16 beacon_interval;
2260 u8 dtim_period;
2261 size_t ie_len;
2262 u8 *ie;
2263 s32 err = 0;
2264
Arend van Sprield96b8012012-12-05 15:26:02 +01002265 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002266 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267 return err;
2268
Arend van Spriel06bb1232012-09-27 14:17:56 +02002269 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002270
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002271 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002272 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002273 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002274 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002275 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002276 goto update_bss_info_out;
2277 }
2278
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002279 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2280 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002281 if (err)
2282 goto update_bss_info_out;
2283
2284 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2285 ie_len = le32_to_cpu(bi->ie_length);
2286 beacon_interval = le16_to_cpu(bi->beacon_period);
2287
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002288 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002289 if (tim)
2290 dtim_period = tim->data[1];
2291 else {
2292 /*
2293 * active scan was done so we could not get dtim
2294 * information out of probe response.
2295 * so we speficially query dtim information to dongle.
2296 */
2297 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002298 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002299 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002300 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002301 goto update_bss_info_out;
2302 }
2303 dtim_period = (u8)var;
2304 }
2305
Arend van Spriel5b435de2011-10-05 13:19:03 +02002306update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002307 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002308 return err;
2309}
2310
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002311static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002312{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002313 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002314
Arend van Sprielc1179032012-10-22 13:55:33 -07002315 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002316 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002317 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002318 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002319 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002320 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2321 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002322}
2323
Hante Meulemane756af52012-09-11 21:18:52 +02002324static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2325{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002326 struct brcmf_cfg80211_info *cfg =
2327 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002328 escan_timeout_work);
2329
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002330 brcmf_notify_escan_complete(cfg,
2331 cfg->escan_info.ndev, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002332}
2333
2334static void brcmf_escan_timeout(unsigned long data)
2335{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002336 struct brcmf_cfg80211_info *cfg =
2337 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002338
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002339 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002340 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002341 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002342 }
2343}
2344
2345static s32
2346brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2347 struct brcmf_bss_info_le *bss_info_le)
2348{
2349 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2350 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2351 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2352 bss_info_le->SSID_len == bss->SSID_len &&
2353 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2354 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2355 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002356 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2357 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2358
Hante Meulemane756af52012-09-11 21:18:52 +02002359 /* preserve max RSSI if the measurements are
2360 * both on-channel or both off-channel
2361 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002362 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002363 bss->RSSI = bss_info_le->RSSI;
2364 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2365 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2366 /* preserve the on-channel rssi measurement
2367 * if the new measurement is off channel
2368 */
2369 bss->RSSI = bss_info_le->RSSI;
2370 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2371 }
2372 return 1;
2373 }
2374 return 0;
2375}
2376
2377static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002378brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002379 const struct brcmf_event_msg *e, void *data)
2380{
Arend van Spriel19937322012-11-05 16:22:32 -08002381 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2382 struct net_device *ndev = ifp->ndev;
Hante Meulemane756af52012-09-11 21:18:52 +02002383 s32 status;
2384 s32 err = 0;
2385 struct brcmf_escan_result_le *escan_result_le;
2386 struct brcmf_bss_info_le *bss_info_le;
2387 struct brcmf_bss_info_le *bss = NULL;
2388 u32 bi_length;
2389 struct brcmf_scan_results *list;
2390 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002391 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002392
Arend van Spriel5c36b992012-11-14 18:46:05 -08002393 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002394
Hante Meulemanf07998952012-11-05 16:22:13 -08002395 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002396 brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
2397 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
Hante Meulemane756af52012-09-11 21:18:52 +02002398 return -EPERM;
2399 }
2400
2401 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002402 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002403 escan_result_le = (struct brcmf_escan_result_le *) data;
2404 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002405 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002406 goto exit;
2407 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002408 if (!cfg->scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002409 brcmf_dbg(SCAN, "result without cfg80211 request\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002410 goto exit;
2411 }
2412
2413 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002414 brcmf_err("Invalid bss_count %d: ignoring\n",
2415 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002416 goto exit;
2417 }
2418 bss_info_le = &escan_result_le->bss_info_le;
2419
2420 bi_length = le32_to_cpu(bss_info_le->length);
2421 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2422 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002423 brcmf_err("Invalid bss_info length %d: ignoring\n",
2424 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002425 goto exit;
2426 }
2427
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002428 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002429 BIT(NL80211_IFTYPE_ADHOC))) {
2430 if (le16_to_cpu(bss_info_le->capability) &
2431 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002432 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002433 goto exit;
2434 }
2435 }
2436
2437 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002438 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002439 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002440 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002441 goto exit;
2442 }
2443
2444 for (i = 0; i < list->count; i++) {
2445 bss = bss ? (struct brcmf_bss_info_le *)
2446 ((unsigned char *)bss +
2447 le32_to_cpu(bss->length)) : list->bss_info_le;
2448 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2449 goto exit;
2450 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002451 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002452 bss_info_le, bi_length);
2453 list->version = le32_to_cpu(bss_info_le->version);
2454 list->buflen += bi_length;
2455 list->count++;
2456 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002457 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2458 if (cfg->scan_request) {
2459 cfg->bss_list = (struct brcmf_scan_results *)
2460 cfg->escan_info.escan_buf;
2461 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002462 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002463 brcmf_notify_escan_complete(cfg, ndev, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002464 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002465 } else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002466 brcmf_err("Unexpected scan result 0x%x\n", status);
Hante Meulemane756af52012-09-11 21:18:52 +02002467 }
2468exit:
2469 return err;
2470}
2471
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002472static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002473{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002474 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2475 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002476 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2477 /* Init scan_timeout timer */
2478 init_timer(&cfg->escan_timeout);
2479 cfg->escan_timeout.data = (unsigned long) cfg;
2480 cfg->escan_timeout.function = brcmf_escan_timeout;
2481 INIT_WORK(&cfg->escan_timeout_work,
2482 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002483}
2484
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002485static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002486{
2487 if (ms < 1000 / HZ) {
2488 cond_resched();
2489 mdelay(ms);
2490 } else {
2491 msleep(ms);
2492 }
2493}
2494
2495static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2496{
Arend van Sprield96b8012012-12-05 15:26:02 +01002497 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002498
Arend van Spriel5b435de2011-10-05 13:19:03 +02002499 return 0;
2500}
2501
2502static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2503 struct cfg80211_wowlan *wow)
2504{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002505 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2506 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002507 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002508
Arend van Sprield96b8012012-12-05 15:26:02 +01002509 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002510
2511 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002512 * if the primary net_device is not READY there is nothing
2513 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002514 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002515 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2516 if (!check_vif_up(vif))
2517 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002518
Arend van Spriel7d641072012-10-22 13:55:39 -07002519 list_for_each_entry(vif, &cfg->vif_list, list) {
2520 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2521 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002522 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002523 * While going to suspend if associated with AP disassociate
2524 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002525 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002526 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002527
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002528 /* Make sure WPA_Supplicant receives all the event
2529 * generated due to DISASSOC call to the fw to keep
2530 * the state fw and WPA_Supplicant state consistent
2531 */
2532 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002533 }
2534
Arend van Spriel7d641072012-10-22 13:55:39 -07002535 /* end any scanning */
2536 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002537 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002538
2539 /* Turn off watchdog timer */
Arend van Spriel7d641072012-10-22 13:55:39 -07002540 brcmf_set_mpc(ndev, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002541
Arend van Spriel7d641072012-10-22 13:55:39 -07002542exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002543 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002544 /* clear any scanning activity */
2545 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002546 return 0;
2547}
2548
2549static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002550brcmf_update_pmklist(struct net_device *ndev,
2551 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2552{
2553 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002554 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002555
Arend van Spriel40c8e952011-10-12 20:51:20 +02002556 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2557
Arend van Spriel16886732012-12-05 15:26:04 +01002558 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002559 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002560 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2561 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002562 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002563 brcmf_dbg(CONN, "%02x\n",
2564 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002565 }
2566
2567 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002568 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2569 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002570
2571 return err;
2572}
2573
2574static s32
2575brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2576 struct cfg80211_pmksa *pmksa)
2577{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002578 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002579 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002580 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002581 s32 err = 0;
2582 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002583 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002584
Arend van Sprield96b8012012-12-05 15:26:02 +01002585 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002586 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002587 return -EIO;
2588
Arend van Spriel40c8e952011-10-12 20:51:20 +02002589 pmkid_len = le32_to_cpu(pmkids->npmkid);
2590 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002591 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2592 break;
2593 if (i < WL_NUM_PMKIDS_MAX) {
2594 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2595 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002596 if (i == pmkid_len) {
2597 pmkid_len++;
2598 pmkids->npmkid = cpu_to_le32(pmkid_len);
2599 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002600 } else
2601 err = -EINVAL;
2602
Arend van Spriel16886732012-12-05 15:26:04 +01002603 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2604 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002605 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002606 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002607
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002608 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002609
Arend van Sprield96b8012012-12-05 15:26:02 +01002610 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002611 return err;
2612}
2613
2614static s32
2615brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2616 struct cfg80211_pmksa *pmksa)
2617{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002618 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002619 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002620 struct pmkid_list pmkid;
2621 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002622 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002623
Arend van Sprield96b8012012-12-05 15:26:02 +01002624 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002625 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002626 return -EIO;
2627
2628 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2629 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2630
Arend van Spriel16886732012-12-05 15:26:04 +01002631 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2632 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002633 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002634 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002635
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002636 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002637 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002638 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002639 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002640 ETH_ALEN))
2641 break;
2642
Arend van Spriel40c8e952011-10-12 20:51:20 +02002643 if ((pmkid_len > 0)
2644 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002645 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002646 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002647 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002648 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2649 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002651 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2652 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002653 WLAN_PMKID_LEN);
2654 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002655 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002656 } else
2657 err = -EINVAL;
2658
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002659 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002660
Arend van Sprield96b8012012-12-05 15:26:02 +01002661 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002662 return err;
2663
2664}
2665
2666static s32
2667brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2668{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002669 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002670 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002671 s32 err = 0;
2672
Arend van Sprield96b8012012-12-05 15:26:02 +01002673 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002674 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002675 return -EIO;
2676
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002677 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2678 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002679
Arend van Sprield96b8012012-12-05 15:26:02 +01002680 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002681 return err;
2682
2683}
2684
Arend van Spriele5806072012-09-19 22:21:08 +02002685/*
2686 * PFN result doesn't have all the info which are
2687 * required by the supplicant
2688 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2689 * via wl_inform_single_bss in the required format. Escan does require the
2690 * scan request in the form of cfg80211_scan_request. For timebeing, create
2691 * cfg80211_scan_request one out of the received PNO event.
2692 */
2693static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002694brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002695 const struct brcmf_event_msg *e, void *data)
2696{
Arend van Spriel19937322012-11-05 16:22:32 -08002697 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2698 struct net_device *ndev = ifp->ndev;
Arend van Spriele5806072012-09-19 22:21:08 +02002699 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2700 struct cfg80211_scan_request *request = NULL;
2701 struct cfg80211_ssid *ssid = NULL;
2702 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002703 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002704 int err = 0;
2705 int channel_req = 0;
2706 int band = 0;
2707 struct brcmf_pno_scanresults_le *pfn_result;
2708 u32 result_count;
2709 u32 status;
2710
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002711 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002712
Arend van Spriel5c36b992012-11-14 18:46:05 -08002713 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002714 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002715 return 0;
2716 }
2717
2718 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2719 result_count = le32_to_cpu(pfn_result->count);
2720 status = le32_to_cpu(pfn_result->status);
2721
2722 /*
2723 * PFN event is limited to fit 512 bytes so we may get
2724 * multiple NET_FOUND events. For now place a warning here.
2725 */
2726 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002727 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002728 if (result_count > 0) {
2729 int i;
2730
2731 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002732 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2733 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002734 if (!request || !ssid || !channel) {
2735 err = -ENOMEM;
2736 goto out_err;
2737 }
2738
2739 request->wiphy = wiphy;
2740 data += sizeof(struct brcmf_pno_scanresults_le);
2741 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2742
2743 for (i = 0; i < result_count; i++) {
2744 netinfo = &netinfo_start[i];
2745 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002746 brcmf_err("Invalid netinfo ptr. index: %d\n",
2747 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002748 err = -EINVAL;
2749 goto out_err;
2750 }
2751
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002752 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2753 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002754 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2755 ssid[i].ssid_len = netinfo->SSID_len;
2756 request->n_ssids++;
2757
2758 channel_req = netinfo->channel;
2759 if (channel_req <= CH_MAX_2G_CHANNEL)
2760 band = NL80211_BAND_2GHZ;
2761 else
2762 band = NL80211_BAND_5GHZ;
2763 channel[i].center_freq =
2764 ieee80211_channel_to_frequency(channel_req,
2765 band);
2766 channel[i].band = band;
2767 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2768 request->channels[i] = &channel[i];
2769 request->n_channels++;
2770 }
2771
2772 /* assign parsed ssid array */
2773 if (request->n_ssids)
2774 request->ssids = &ssid[0];
2775
Arend van Sprielc1179032012-10-22 13:55:33 -07002776 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002777 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002778 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002779 }
2780
Arend van Sprielc1179032012-10-22 13:55:33 -07002781 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002782 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002783 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002784 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002785 goto out_err;
2786 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002787 cfg->sched_escan = true;
2788 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002789 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002790 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002791 goto out_err;
2792 }
2793
2794 kfree(ssid);
2795 kfree(channel);
2796 kfree(request);
2797 return 0;
2798
2799out_err:
2800 kfree(ssid);
2801 kfree(channel);
2802 kfree(request);
2803 cfg80211_sched_scan_stopped(wiphy);
2804 return err;
2805}
2806
Arend van Spriele5806072012-09-19 22:21:08 +02002807static int brcmf_dev_pno_clean(struct net_device *ndev)
2808{
Arend van Spriele5806072012-09-19 22:21:08 +02002809 int ret;
2810
2811 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002812 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002813 if (ret == 0) {
2814 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002815 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
2816 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002817 }
2818 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002819 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002820
2821 return ret;
2822}
2823
2824static int brcmf_dev_pno_config(struct net_device *ndev)
2825{
2826 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02002827
2828 memset(&pfn_param, 0, sizeof(pfn_param));
2829 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
2830
2831 /* set extra pno params */
2832 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
2833 pfn_param.repeat = BRCMF_PNO_REPEAT;
2834 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
2835
2836 /* set up pno scan fr */
2837 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
2838
Arend van Sprielac24be62012-10-22 10:36:23 -07002839 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
2840 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02002841}
2842
2843static int
2844brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
2845 struct net_device *ndev,
2846 struct cfg80211_sched_scan_request *request)
2847{
Arend van Sprielc1179032012-10-22 13:55:33 -07002848 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002849 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002850 struct brcmf_pno_net_param_le pfn;
2851 int i;
2852 int ret = 0;
2853
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002854 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
2855 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07002856 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002857 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002858 return -EAGAIN;
2859 }
2860
2861 if (!request || !request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002862 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
2863 request ? request->n_ssids : 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002864 return -EINVAL;
2865 }
2866
2867 if (request->n_ssids > 0) {
2868 for (i = 0; i < request->n_ssids; i++) {
2869 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002870 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
2871 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002872
2873 /*
2874 * match_set ssids is a supert set of n_ssid list,
2875 * so we need not add these set seperately.
2876 */
2877 }
2878 }
2879
2880 if (request->n_match_sets > 0) {
2881 /* clean up everything */
2882 ret = brcmf_dev_pno_clean(ndev);
2883 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002884 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002885 return ret;
2886 }
2887
2888 /* configure pno */
2889 ret = brcmf_dev_pno_config(ndev);
2890 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002891 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002892 return -EINVAL;
2893 }
2894
2895 /* configure each match set */
2896 for (i = 0; i < request->n_match_sets; i++) {
2897 struct cfg80211_ssid *ssid;
2898 u32 ssid_len;
2899
2900 ssid = &request->match_sets[i].ssid;
2901 ssid_len = ssid->ssid_len;
2902
2903 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002904 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002905 continue;
2906 }
2907 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
2908 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
2909 pfn.wsec = cpu_to_le32(0);
2910 pfn.infra = cpu_to_le32(1);
2911 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
2912 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
2913 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07002914 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07002915 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002916 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
2917 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002918 }
2919 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07002920 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002921 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002922 return -EINVAL;
2923 }
2924 } else {
2925 return -EINVAL;
2926 }
2927
2928 return 0;
2929}
2930
2931static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2932 struct net_device *ndev)
2933{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002934 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002935
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002936 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002937 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002938 if (cfg->sched_escan)
2939 brcmf_notify_escan_complete(cfg, ndev, true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02002940 return 0;
2941}
Arend van Spriele5806072012-09-19 22:21:08 +02002942
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002943#ifdef CONFIG_NL80211_TESTMODE
2944static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
2945{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002946 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07002947 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002948 struct brcmf_dcmd *dcmd = data;
2949 struct sk_buff *reply;
2950 int ret;
2951
Arend van Sprield96b8012012-12-05 15:26:02 +01002952 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
2953 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07002954
2955 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07002956 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
2957 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07002958 else
Arend van Sprielac24be62012-10-22 10:36:23 -07002959 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
2960 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002961 if (ret == 0) {
2962 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
2963 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
2964 ret = cfg80211_testmode_reply(reply);
2965 }
2966 return ret;
2967}
2968#endif
2969
Hante Meuleman1f170112013-02-06 18:40:38 +01002970static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02002971{
2972 s32 err;
2973
2974 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07002975 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02002976 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002977 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002978 return err;
2979 }
2980 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07002981 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02002982 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002983 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002984 return err;
2985 }
2986 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07002987 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02002988 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002989 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002990 return err;
2991 }
2992
2993 return 0;
2994}
2995
2996static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
2997{
2998 if (is_rsn_ie)
2999 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3000
3001 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3002}
3003
3004static s32
3005brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003006 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003007{
Arend van Sprielac24be62012-10-22 10:36:23 -07003008 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003009 u32 auth = 0; /* d11 open authentication */
3010 u16 count;
3011 s32 err = 0;
3012 s32 len = 0;
3013 u32 i;
3014 u32 wsec;
3015 u32 pval = 0;
3016 u32 gval = 0;
3017 u32 wpa_auth = 0;
3018 u32 offset;
3019 u8 *data;
3020 u16 rsn_cap;
3021 u32 wme_bss_disable;
3022
Arend van Sprield96b8012012-12-05 15:26:02 +01003023 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003024 if (wpa_ie == NULL)
3025 goto exit;
3026
3027 len = wpa_ie->len + TLV_HDR_LEN;
3028 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003029 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003030 if (!is_rsn_ie)
3031 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003032 else
3033 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003034
3035 /* check for multicast cipher suite */
3036 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3037 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003038 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003039 goto exit;
3040 }
3041
3042 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3043 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003044 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003045 goto exit;
3046 }
3047 offset += TLV_OUI_LEN;
3048
3049 /* pick up multicast cipher */
3050 switch (data[offset]) {
3051 case WPA_CIPHER_NONE:
3052 gval = 0;
3053 break;
3054 case WPA_CIPHER_WEP_40:
3055 case WPA_CIPHER_WEP_104:
3056 gval = WEP_ENABLED;
3057 break;
3058 case WPA_CIPHER_TKIP:
3059 gval = TKIP_ENABLED;
3060 break;
3061 case WPA_CIPHER_AES_CCM:
3062 gval = AES_ENABLED;
3063 break;
3064 default:
3065 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003066 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003067 goto exit;
3068 }
3069
3070 offset++;
3071 /* walk thru unicast cipher list and pick up what we recognize */
3072 count = data[offset] + (data[offset + 1] << 8);
3073 offset += WPA_IE_SUITE_COUNT_LEN;
3074 /* Check for unicast suite(s) */
3075 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3076 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003077 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003078 goto exit;
3079 }
3080 for (i = 0; i < count; i++) {
3081 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3082 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003083 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003084 goto exit;
3085 }
3086 offset += TLV_OUI_LEN;
3087 switch (data[offset]) {
3088 case WPA_CIPHER_NONE:
3089 break;
3090 case WPA_CIPHER_WEP_40:
3091 case WPA_CIPHER_WEP_104:
3092 pval |= WEP_ENABLED;
3093 break;
3094 case WPA_CIPHER_TKIP:
3095 pval |= TKIP_ENABLED;
3096 break;
3097 case WPA_CIPHER_AES_CCM:
3098 pval |= AES_ENABLED;
3099 break;
3100 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003101 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003102 }
3103 offset++;
3104 }
3105 /* walk thru auth management suite list and pick up what we recognize */
3106 count = data[offset] + (data[offset + 1] << 8);
3107 offset += WPA_IE_SUITE_COUNT_LEN;
3108 /* Check for auth key management suite(s) */
3109 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3110 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003111 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003112 goto exit;
3113 }
3114 for (i = 0; i < count; i++) {
3115 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3116 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003117 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003118 goto exit;
3119 }
3120 offset += TLV_OUI_LEN;
3121 switch (data[offset]) {
3122 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003123 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003124 wpa_auth |= WPA_AUTH_NONE;
3125 break;
3126 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003127 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003128 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3129 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3130 break;
3131 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003132 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003133 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3134 (wpa_auth |= WPA_AUTH_PSK);
3135 break;
3136 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003137 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003138 }
3139 offset++;
3140 }
3141
3142 if (is_rsn_ie) {
3143 wme_bss_disable = 1;
3144 if ((offset + RSN_CAP_LEN) <= len) {
3145 rsn_cap = data[offset] + (data[offset + 1] << 8);
3146 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3147 wme_bss_disable = 0;
3148 }
3149 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003150 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003151 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003152 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003153 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003154 goto exit;
3155 }
3156 }
3157 /* FOR WPS , set SES_OW_ENABLED */
3158 wsec = (pval | gval | SES_OW_ENABLED);
3159
3160 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003161 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003162 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003163 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003164 goto exit;
3165 }
3166 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003167 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003168 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003169 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003170 goto exit;
3171 }
3172 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003173 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003174 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003175 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003176 goto exit;
3177 }
3178
3179exit:
3180 return err;
3181}
3182
3183static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003184brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003185 struct parsed_vndr_ies *vndr_ies)
3186{
3187 s32 err = 0;
3188 struct brcmf_vs_tlv *vndrie;
3189 struct brcmf_tlv *ie;
3190 struct parsed_vndr_ie_info *parsed_info;
3191 s32 remaining_len;
3192
3193 remaining_len = (s32)vndr_ie_len;
3194 memset(vndr_ies, 0, sizeof(*vndr_ies));
3195
3196 ie = (struct brcmf_tlv *)vndr_ie_buf;
3197 while (ie) {
3198 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3199 goto next;
3200 vndrie = (struct brcmf_vs_tlv *)ie;
3201 /* len should be bigger than OUI length + one */
3202 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003203 brcmf_err("invalid vndr ie. length is too small %d\n",
3204 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003205 goto next;
3206 }
3207 /* if wpa or wme ie, do not add ie */
3208 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3209 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3210 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003211 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003212 goto next;
3213 }
3214
3215 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3216
3217 /* save vndr ie information */
3218 parsed_info->ie_ptr = (char *)vndrie;
3219 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3220 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3221
3222 vndr_ies->count++;
3223
Arend van Sprield96b8012012-12-05 15:26:02 +01003224 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3225 parsed_info->vndrie.oui[0],
3226 parsed_info->vndrie.oui[1],
3227 parsed_info->vndrie.oui[2],
3228 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003229
3230 if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
3231 break;
3232next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003233 remaining_len -= (ie->len + TLV_HDR_LEN);
3234 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003235 ie = NULL;
3236 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003237 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3238 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003239 }
3240 return err;
3241}
3242
3243static u32
3244brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3245{
3246
3247 __le32 iecount_le;
3248 __le32 pktflag_le;
3249
3250 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3251 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3252
3253 iecount_le = cpu_to_le32(1);
3254 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3255
3256 pktflag_le = cpu_to_le32(pktflag);
3257 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3258
3259 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3260
3261 return ie_len + VNDR_IE_HDR_SIZE;
3262}
3263
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003264static
Arend van Spriel1332e262012-11-05 16:22:18 -08003265s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3266 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003267{
Arend van Spriel1332e262012-11-05 16:22:18 -08003268 struct brcmf_if *ifp;
3269 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003270 s32 err = 0;
3271 u8 *iovar_ie_buf;
3272 u8 *curr_ie_buf;
3273 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003274 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003275 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003276 u32 del_add_ie_buf_len = 0;
3277 u32 total_ie_buf_len = 0;
3278 u32 parsed_ie_buf_len = 0;
3279 struct parsed_vndr_ies old_vndr_ies;
3280 struct parsed_vndr_ies new_vndr_ies;
3281 struct parsed_vndr_ie_info *vndrie_info;
3282 s32 i;
3283 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003284 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003285
Arend van Spriel1332e262012-11-05 16:22:18 -08003286 if (!vif)
3287 return -ENODEV;
3288 ifp = vif->ifp;
3289 saved_ie = &vif->saved_ie;
3290
Arend van Sprield96b8012012-12-05 15:26:02 +01003291 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003292 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3293 if (!iovar_ie_buf)
3294 return -ENOMEM;
3295 curr_ie_buf = iovar_ie_buf;
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003296 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003297 switch (pktflag) {
3298 case VNDR_IE_PRBRSP_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003299 mgmt_ie_buf = saved_ie->probe_res_ie;
3300 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3301 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003302 break;
3303 case VNDR_IE_BEACON_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003304 mgmt_ie_buf = saved_ie->beacon_ie;
3305 mgmt_ie_len = &saved_ie->beacon_ie_len;
3306 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003307 break;
3308 default:
3309 err = -EPERM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003310 brcmf_err("not suitable type\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003311 goto exit;
3312 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003313 } else {
3314 err = -EPERM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003315 brcmf_err("not suitable type\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003316 goto exit;
3317 }
3318
3319 if (vndr_ie_len > mgmt_ie_buf_len) {
3320 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003321 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003322 goto exit;
3323 }
3324
3325 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3326 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3327 ptr = curr_ie_buf;
3328 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3329 for (i = 0; i < new_vndr_ies.count; i++) {
3330 vndrie_info = &new_vndr_ies.ie_info[i];
3331 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3332 vndrie_info->ie_len);
3333 parsed_ie_buf_len += vndrie_info->ie_len;
3334 }
3335 }
3336
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003337 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003338 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3339 (memcmp(mgmt_ie_buf, curr_ie_buf,
3340 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003341 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003342 goto exit;
3343 }
3344
3345 /* parse old vndr_ie */
3346 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3347
3348 /* make a command to delete old ie */
3349 for (i = 0; i < old_vndr_ies.count; i++) {
3350 vndrie_info = &old_vndr_ies.ie_info[i];
3351
Arend van Sprield96b8012012-12-05 15:26:02 +01003352 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3353 vndrie_info->vndrie.id,
3354 vndrie_info->vndrie.len,
3355 vndrie_info->vndrie.oui[0],
3356 vndrie_info->vndrie.oui[1],
3357 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003358
3359 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3360 vndrie_info->ie_ptr,
3361 vndrie_info->ie_len,
3362 "del");
3363 curr_ie_buf += del_add_ie_buf_len;
3364 total_ie_buf_len += del_add_ie_buf_len;
3365 }
3366 }
3367
3368 *mgmt_ie_len = 0;
3369 /* Add if there is any extra IE */
3370 if (mgmt_ie_buf && parsed_ie_buf_len) {
3371 ptr = mgmt_ie_buf;
3372
3373 remained_buf_len = mgmt_ie_buf_len;
3374
3375 /* make a command to add new ie */
3376 for (i = 0; i < new_vndr_ies.count; i++) {
3377 vndrie_info = &new_vndr_ies.ie_info[i];
3378
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003379 /* verify remained buf size before copy data */
3380 if (remained_buf_len < (vndrie_info->vndrie.len +
3381 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003382 brcmf_err("no space in mgmt_ie_buf: len left %d",
3383 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003384 break;
3385 }
3386 remained_buf_len -= (vndrie_info->ie_len +
3387 VNDR_IE_VSIE_OFFSET);
3388
Arend van Sprield96b8012012-12-05 15:26:02 +01003389 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3390 vndrie_info->vndrie.id,
3391 vndrie_info->vndrie.len,
3392 vndrie_info->vndrie.oui[0],
3393 vndrie_info->vndrie.oui[1],
3394 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003395
3396 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3397 vndrie_info->ie_ptr,
3398 vndrie_info->ie_len,
3399 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003400
3401 /* save the parsed IE in wl struct */
3402 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3403 vndrie_info->ie_len);
3404 *mgmt_ie_len += vndrie_info->ie_len;
3405
3406 curr_ie_buf += del_add_ie_buf_len;
3407 total_ie_buf_len += del_add_ie_buf_len;
3408 }
3409 }
3410 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003411 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003412 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003413 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003414 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003415 }
3416
3417exit:
3418 kfree(iovar_ie_buf);
3419 return err;
3420}
3421
3422static s32
3423brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3424 struct cfg80211_ap_settings *settings)
3425{
3426 s32 ie_offset;
Arend van Sprielac24be62012-10-22 10:36:23 -07003427 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003428 struct brcmf_tlv *ssid_ie;
3429 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003430 s32 err = -EPERM;
3431 struct brcmf_tlv *rsn_ie;
3432 struct brcmf_vs_tlv *wpa_ie;
3433 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003434
Arend van Sprield96b8012012-12-05 15:26:02 +01003435 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3436 cfg80211_get_chandef_type(&settings->chandef),
3437 settings->beacon_interval,
3438 settings->dtim_period);
3439 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3440 settings->ssid, settings->ssid_len, settings->auth_type,
3441 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003442
Arend van Sprielc1179032012-10-22 13:55:33 -07003443 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003444 brcmf_err("Not in AP creation mode\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003445 return -EPERM;
3446 }
3447
3448 memset(&ssid_le, 0, sizeof(ssid_le));
3449 if (settings->ssid == NULL || settings->ssid_len == 0) {
3450 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3451 ssid_ie = brcmf_parse_tlvs(
3452 (u8 *)&settings->beacon.head[ie_offset],
3453 settings->beacon.head_len - ie_offset,
3454 WLAN_EID_SSID);
3455 if (!ssid_ie)
3456 return -EINVAL;
3457
3458 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3459 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003460 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003461 } else {
3462 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3463 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3464 }
3465
3466 brcmf_set_mpc(ndev, 0);
Arend van Sprielac24be62012-10-22 10:36:23 -07003467 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003468 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003469 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003470 goto exit;
3471 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003472 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003473 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003474 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003475 goto exit;
3476 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003477 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003478 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003479 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003480 goto exit;
3481 }
3482
3483 /* find the RSN_IE */
3484 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3485 settings->beacon.tail_len, WLAN_EID_RSN);
3486
3487 /* find the WPA_IE */
3488 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3489 settings->beacon.tail_len);
3490
Hante Meuleman1a873342012-09-27 14:17:54 +02003491 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003492 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003493 if (wpa_ie != NULL) {
3494 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003495 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003496 if (err < 0)
3497 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003498 } else {
3499 /* RSN IE */
3500 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003501 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003502 if (err < 0)
3503 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003504 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003505 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003506 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003507 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003508 }
3509 /* Set Beacon IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003510 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
3511 VNDR_IE_BEACON_FLAG,
3512 settings->beacon.tail,
3513 settings->beacon.tail_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003514 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003515 brcmf_err("Set Beacon IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003516 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003517 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003518
3519 /* Set Probe Response IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003520 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
3521 VNDR_IE_PRBRSP_FLAG,
3522 settings->beacon.proberesp_ies,
3523 settings->beacon.proberesp_ies_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003524 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003525 brcmf_err("Set Probe Resp IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003526 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003527 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003528
3529 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003530 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003531 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003532 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003533 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003534 goto exit;
3535 }
3536 }
3537 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003538 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003539 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003540 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003541 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003542 goto exit;
3543 }
3544 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003545 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003546 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003547 brcmf_err("BRCMF_C_UP error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003548 goto exit;
3549 }
3550
3551 memset(&join_params, 0, sizeof(join_params));
3552 /* join parameters starts with ssid */
3553 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3554 /* create softap */
Arend van Sprielac24be62012-10-22 10:36:23 -07003555 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3556 &join_params, sizeof(join_params));
Hante Meuleman1a873342012-09-27 14:17:54 +02003557 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003558 brcmf_err("SET SSID error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003559 goto exit;
3560 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003561 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3562 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003563
3564exit:
3565 if (err)
3566 brcmf_set_mpc(ndev, 1);
3567 return err;
3568}
3569
3570static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3571{
Arend van Sprielc1179032012-10-22 13:55:33 -07003572 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003573 s32 err = -EPERM;
3574
Arend van Sprield96b8012012-12-05 15:26:02 +01003575 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003576
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003577 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003578 /* Due to most likely deauths outstanding we sleep */
3579 /* first to make sure they get processed by fw. */
3580 msleep(400);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003581 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003582 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003583 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003584 goto exit;
3585 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003586 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003587 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003588 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003589 goto exit;
3590 }
3591 brcmf_set_mpc(ndev, 1);
Arend van Sprielc1179032012-10-22 13:55:33 -07003592 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3593 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003594 }
3595exit:
3596 return err;
3597}
3598
3599static int
3600brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3601 u8 *mac)
3602{
3603 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003604 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003605 s32 err;
3606
3607 if (!mac)
3608 return -EFAULT;
3609
Arend van Sprield96b8012012-12-05 15:26:02 +01003610 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003611
Arend van Sprielce81e312012-10-22 13:55:37 -07003612 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003613 return -EIO;
3614
3615 memcpy(&scbval.ea, mac, ETH_ALEN);
3616 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003617 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003618 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003619 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003620 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003621
Arend van Sprield96b8012012-12-05 15:26:02 +01003622 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003623 return err;
3624}
3625
Arend van Spriel5b435de2011-10-05 13:19:03 +02003626static struct cfg80211_ops wl_cfg80211_ops = {
3627 .change_virtual_intf = brcmf_cfg80211_change_iface,
3628 .scan = brcmf_cfg80211_scan,
3629 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
3630 .join_ibss = brcmf_cfg80211_join_ibss,
3631 .leave_ibss = brcmf_cfg80211_leave_ibss,
3632 .get_station = brcmf_cfg80211_get_station,
3633 .set_tx_power = brcmf_cfg80211_set_tx_power,
3634 .get_tx_power = brcmf_cfg80211_get_tx_power,
3635 .add_key = brcmf_cfg80211_add_key,
3636 .del_key = brcmf_cfg80211_del_key,
3637 .get_key = brcmf_cfg80211_get_key,
3638 .set_default_key = brcmf_cfg80211_config_default_key,
3639 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
3640 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003641 .connect = brcmf_cfg80211_connect,
3642 .disconnect = brcmf_cfg80211_disconnect,
3643 .suspend = brcmf_cfg80211_suspend,
3644 .resume = brcmf_cfg80211_resume,
3645 .set_pmksa = brcmf_cfg80211_set_pmksa,
3646 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003647 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02003648 .start_ap = brcmf_cfg80211_start_ap,
3649 .stop_ap = brcmf_cfg80211_stop_ap,
3650 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02003651 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
3652 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003653#ifdef CONFIG_NL80211_TESTMODE
3654 .testmode_cmd = brcmf_cfg80211_testmode
3655#endif
Arend van Spriel5b435de2011-10-05 13:19:03 +02003656};
3657
3658static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
3659{
3660 s32 err = 0;
3661
3662 switch (mode) {
3663 case WL_MODE_BSS:
3664 return NL80211_IFTYPE_STATION;
3665 case WL_MODE_IBSS:
3666 return NL80211_IFTYPE_ADHOC;
3667 default:
3668 return NL80211_IFTYPE_UNSPECIFIED;
3669 }
3670
3671 return err;
3672}
3673
Arend van Spriele5806072012-09-19 22:21:08 +02003674static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
3675{
Arend van Spriele5806072012-09-19 22:21:08 +02003676 /* scheduled scan settings */
3677 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
3678 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
3679 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3680 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02003681}
3682
Arend van Spriel3eacf862012-10-22 13:55:30 -07003683static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003684{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003685 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003686 s32 err = 0;
3687
Arend van Spriel3eacf862012-10-22 13:55:30 -07003688 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
3689 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003690 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07003691 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003692 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003693 set_wiphy_dev(wiphy, phydev);
3694 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
3695 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
3696 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3697 BIT(NL80211_IFTYPE_ADHOC) |
3698 BIT(NL80211_IFTYPE_AP);
3699 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3700 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
Arend van Spriel5b435de2011-10-05 13:19:03 +02003701 * it as 11a by default.
3702 * This will be updated with
3703 * 11n phy tables in
3704 * "ifconfig up"
3705 * if phy has 11n capability
3706 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07003707 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3708 wiphy->cipher_suites = __wl_cipher_suites;
3709 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
3710 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
Arend van Spriel5b435de2011-10-05 13:19:03 +02003711 * save mode
3712 * by default
3713 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07003714 brcmf_wiphy_pno_params(wiphy);
3715 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003716 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003717 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003718 wiphy_free(wiphy);
3719 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003720 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003721 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003722}
3723
Arend van Spriel3eacf862012-10-22 13:55:30 -07003724static
3725struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
3726 struct net_device *netdev,
3727 s32 mode, bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003728{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003729 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003730
Arend van Spriel3eacf862012-10-22 13:55:30 -07003731 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
3732 return ERR_PTR(-ENOSPC);
3733
3734 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
3735 if (!vif)
3736 return ERR_PTR(-ENOMEM);
3737
3738 vif->wdev.wiphy = cfg->wiphy;
3739 vif->wdev.netdev = netdev;
3740 vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
3741
3742 if (netdev) {
3743 vif->ifp = netdev_priv(netdev);
3744 netdev->ieee80211_ptr = &vif->wdev;
3745 SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003746 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003747
3748 vif->mode = mode;
3749 vif->pm_block = pm_block;
3750 vif->roam_off = -1;
3751
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07003752 brcmf_init_prof(&vif->profile);
3753
Arend van Spriel3eacf862012-10-22 13:55:30 -07003754 list_add_tail(&vif->list, &cfg->vif_list);
3755 cfg->vif_cnt++;
3756 return vif;
3757}
3758
3759static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
3760{
3761 struct brcmf_cfg80211_info *cfg;
3762 struct wiphy *wiphy;
3763
3764 wiphy = vif->wdev.wiphy;
3765 cfg = wiphy_priv(wiphy);
3766 list_del(&vif->list);
3767 cfg->vif_cnt--;
3768
3769 kfree(vif);
3770 if (!cfg->vif_cnt) {
3771 wiphy_unregister(wiphy);
3772 wiphy_free(wiphy);
3773 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003774}
3775
Arend van Spriel903e0ee2012-11-28 21:44:11 +01003776static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003777{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003778 u32 event = e->event_code;
3779 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003780
3781 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01003782 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003783 return true;
3784 }
3785
3786 return false;
3787}
3788
Arend van Spriel903e0ee2012-11-28 21:44:11 +01003789static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003790{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003791 u32 event = e->event_code;
3792 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003793
3794 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01003795 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003796 return true;
3797 }
3798 return false;
3799}
3800
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003801static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003802 const struct brcmf_event_msg *e)
3803{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003804 u32 event = e->event_code;
3805 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003806
3807 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01003808 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
3809 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003810 return true;
3811 }
3812
3813 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01003814 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003815 return true;
3816 }
3817
3818 return false;
3819}
3820
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003821static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003822{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003823 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003824
3825 kfree(conn_info->req_ie);
3826 conn_info->req_ie = NULL;
3827 conn_info->req_ie_len = 0;
3828 kfree(conn_info->resp_ie);
3829 conn_info->resp_ie = NULL;
3830 conn_info->resp_ie_len = 0;
3831}
3832
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003833static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003834{
Arend van Sprielac24be62012-10-22 10:36:23 -07003835 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielc4e382d2011-10-12 20:51:21 +02003836 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003837 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003838 u32 req_len;
3839 u32 resp_len;
3840 s32 err = 0;
3841
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003842 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003843
Arend van Sprielac24be62012-10-22 10:36:23 -07003844 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
3845 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003846 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003847 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003848 return err;
3849 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02003850 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003851 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02003852 req_len = le32_to_cpu(assoc_info->req_len);
3853 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003854 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003855 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003856 cfg->extra_buf,
3857 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003858 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003859 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003860 return err;
3861 }
3862 conn_info->req_ie_len = req_len;
3863 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003864 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003865 GFP_KERNEL);
3866 } else {
3867 conn_info->req_ie_len = 0;
3868 conn_info->req_ie = NULL;
3869 }
3870 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003871 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003872 cfg->extra_buf,
3873 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003874 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003875 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003876 return err;
3877 }
3878 conn_info->resp_ie_len = resp_len;
3879 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003880 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003881 GFP_KERNEL);
3882 } else {
3883 conn_info->resp_ie_len = 0;
3884 conn_info->resp_ie = NULL;
3885 }
Arend van Spriel16886732012-12-05 15:26:04 +01003886 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
3887 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003888
3889 return err;
3890}
3891
3892static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003893brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003894 struct net_device *ndev,
3895 const struct brcmf_event_msg *e)
3896{
Arend van Sprielc1179032012-10-22 13:55:33 -07003897 struct brcmf_if *ifp = netdev_priv(ndev);
3898 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003899 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
3900 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07003901 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003902 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07003903 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003904 u32 freq;
3905 s32 err = 0;
3906 u32 target_channel;
Franky Lina180b832012-10-10 11:13:09 -07003907 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003908
Arend van Sprield96b8012012-12-05 15:26:02 +01003909 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003910
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003911 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02003912 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003913 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003914
Franky Lina180b832012-10-10 11:13:09 -07003915 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
3916 if (buf == NULL) {
3917 err = -ENOMEM;
3918 goto done;
3919 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003920
Franky Lina180b832012-10-10 11:13:09 -07003921 /* data sent to dongle has to be little endian */
3922 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07003923 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07003924 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07003925
3926 if (err)
3927 goto done;
3928
3929 bi = (struct brcmf_bss_info_le *)(buf + 4);
3930 target_channel = bi->ctl_ch ? bi->ctl_ch :
3931 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003932
3933 if (target_channel <= CH_MAX_2G_CHANNEL)
3934 band = wiphy->bands[IEEE80211_BAND_2GHZ];
3935 else
3936 band = wiphy->bands[IEEE80211_BAND_5GHZ];
3937
3938 freq = ieee80211_channel_to_frequency(target_channel, band->band);
3939 notify_channel = ieee80211_get_channel(wiphy, freq);
3940
Franky Lina180b832012-10-10 11:13:09 -07003941done:
3942 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02003943 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003944 conn_info->req_ie, conn_info->req_ie_len,
3945 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01003946 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003947
Arend van Sprielc1179032012-10-22 13:55:33 -07003948 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01003949 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003950 return err;
3951}
3952
3953static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003954brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003955 struct net_device *ndev, const struct brcmf_event_msg *e,
3956 bool completed)
3957{
Arend van Sprielc1179032012-10-22 13:55:33 -07003958 struct brcmf_if *ifp = netdev_priv(ndev);
3959 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003960 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003961 s32 err = 0;
3962
Arend van Sprield96b8012012-12-05 15:26:02 +01003963 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003964
Arend van Sprielc1179032012-10-22 13:55:33 -07003965 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
3966 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003967 if (completed) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003968 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02003969 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003970 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003971 }
3972 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02003973 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003974 conn_info->req_ie,
3975 conn_info->req_ie_len,
3976 conn_info->resp_ie,
3977 conn_info->resp_ie_len,
3978 completed ? WLAN_STATUS_SUCCESS :
3979 WLAN_STATUS_AUTH_TIMEOUT,
3980 GFP_KERNEL);
3981 if (completed)
Arend van Sprielc1179032012-10-22 13:55:33 -07003982 set_bit(BRCMF_VIF_STATUS_CONNECTED,
3983 &ifp->vif->sme_state);
Arend van Spriel16886732012-12-05 15:26:04 +01003984 brcmf_dbg(CONN, "Report connect result - connection %s\n",
3985 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003986 }
Arend van Sprield96b8012012-12-05 15:26:02 +01003987 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003988 return err;
3989}
3990
3991static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003992brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02003993 struct net_device *ndev,
3994 const struct brcmf_event_msg *e, void *data)
3995{
Hante Meuleman7ee29602013-02-06 18:40:43 +01003996 static int generation;
Arend van Spriel5c36b992012-11-14 18:46:05 -08003997 u32 event = e->event_code;
3998 u32 reason = e->reason;
Hante Meuleman1a873342012-09-27 14:17:54 +02003999 struct station_info sinfo;
4000
Arend van Spriel16886732012-12-05 15:26:04 +01004001 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Hante Meuleman1a873342012-09-27 14:17:54 +02004002
Hante Meuleman1a873342012-09-27 14:17:54 +02004003 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
Hante Meuleman7ee29602013-02-06 18:40:43 +01004004 (reason == BRCMF_E_STATUS_SUCCESS)) {
4005 memset(&sinfo, 0, sizeof(sinfo));
Hante Meuleman1a873342012-09-27 14:17:54 +02004006 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4007 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004008 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004009 return -EINVAL;
4010 }
4011 sinfo.assoc_req_ies = data;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004012 sinfo.assoc_req_ies_len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004013 generation++;
4014 sinfo.generation = generation;
Hante Meuleman7ee29602013-02-06 18:40:43 +01004015 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004016 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4017 (event == BRCMF_E_DEAUTH_IND) ||
4018 (event == BRCMF_E_DEAUTH)) {
Hante Meuleman7ee29602013-02-06 18:40:43 +01004019 cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
Hante Meuleman1a873342012-09-27 14:17:54 +02004020 }
Hante Meuleman7ee29602013-02-06 18:40:43 +01004021 return 0;
Hante Meuleman1a873342012-09-27 14:17:54 +02004022}
4023
4024static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004025brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004026 const struct brcmf_event_msg *e, void *data)
4027{
Arend van Spriel19937322012-11-05 16:22:32 -08004028 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4029 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004030 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004031 s32 err = 0;
4032
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004033 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004034 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004035 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004036 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004037 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004038 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004039 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004040 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004041 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4042 &ifp->vif->sme_state);
4043 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4044 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004045 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004046 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004047 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004048 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004049 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004050 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004051 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004052 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004053 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004054 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004055 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004056 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004057 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004058 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004059 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004060 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4061 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004062 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004063 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004064 }
4065
4066 return err;
4067}
4068
4069static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004070brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004071 const struct brcmf_event_msg *e, void *data)
4072{
Arend van Spriel19937322012-11-05 16:22:32 -08004073 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004074 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004075 u32 event = e->event_code;
4076 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004077
4078 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004079 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004080 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004081 else
Arend van Spriel19937322012-11-05 16:22:32 -08004082 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004083 }
4084
4085 return err;
4086}
4087
4088static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004089brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004090 const struct brcmf_event_msg *e, void *data)
4091{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004092 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004093 enum nl80211_key_type key_type;
4094
4095 if (flags & BRCMF_EVENT_MSG_GROUP)
4096 key_type = NL80211_KEYTYPE_GROUP;
4097 else
4098 key_type = NL80211_KEYTYPE_PAIRWISE;
4099
Arend van Spriel19937322012-11-05 16:22:32 -08004100 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004101 NULL, GFP_KERNEL);
4102
4103 return 0;
4104}
4105
Arend van Spriel5b435de2011-10-05 13:19:03 +02004106static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4107{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004108 conf->frag_threshold = (u32)-1;
4109 conf->rts_threshold = (u32)-1;
4110 conf->retry_short = (u32)-1;
4111 conf->retry_long = (u32)-1;
4112 conf->tx_power = -1;
4113}
4114
Arend van Spriel5c36b992012-11-14 18:46:05 -08004115static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004116{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004117 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4118 brcmf_notify_connect_status);
4119 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4120 brcmf_notify_connect_status);
4121 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4122 brcmf_notify_connect_status);
4123 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4124 brcmf_notify_connect_status);
4125 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4126 brcmf_notify_connect_status);
4127 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4128 brcmf_notify_connect_status);
4129 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4130 brcmf_notify_roaming_status);
4131 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4132 brcmf_notify_mic_status);
4133 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4134 brcmf_notify_connect_status);
4135 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4136 brcmf_notify_sched_scan_results);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004137}
4138
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004139static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004140{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004141 kfree(cfg->conf);
4142 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004143 kfree(cfg->escan_ioctl_buf);
4144 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004145 kfree(cfg->extra_buf);
4146 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004147 kfree(cfg->pmk_list);
4148 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004149}
4150
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004151static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004152{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004153 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4154 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004155 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004156 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4157 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004158 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004159 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4160 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004161 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004162 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4163 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004164 goto init_priv_mem_out;
4165
4166 return 0;
4167
4168init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004169 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004170
4171 return -ENOMEM;
4172}
4173
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004174static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004175{
4176 s32 err = 0;
4177
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004178 cfg->scan_request = NULL;
4179 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004180 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004181 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004182 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004183 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004184 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004185 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004186 if (err)
4187 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004188 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004189 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004190 brcmf_init_escan(cfg);
4191 brcmf_init_conf(cfg->conf);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004192
4193 return err;
4194}
4195
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004196static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004197{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004198 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004199 brcmf_abort_scanning(cfg);
4200 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004201}
4202
Arend van Sprield9cb2592012-12-05 15:25:54 +01004203struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4204 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004205{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004206 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004207 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004208 struct wiphy *wiphy;
4209 struct brcmf_cfg80211_vif *vif;
4210 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004211 s32 err = 0;
4212
4213 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004214 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004215 return NULL;
4216 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004217
Arend van Spriel3eacf862012-10-22 13:55:30 -07004218 ifp = netdev_priv(ndev);
4219 wiphy = brcmf_setup_wiphy(busdev);
4220 if (IS_ERR(wiphy))
4221 return NULL;
4222
4223 cfg = wiphy_priv(wiphy);
4224 cfg->wiphy = wiphy;
4225 cfg->pub = drvr;
4226 INIT_LIST_HEAD(&cfg->vif_list);
4227
4228 vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
4229 if (IS_ERR(vif)) {
4230 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004231 return NULL;
4232 }
4233
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004234 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004235 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004236 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004237 goto cfg80211_attach_out;
4238 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004239
Arend van Spriel3eacf862012-10-22 13:55:30 -07004240 ifp->vif = vif;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004241 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004242
4243cfg80211_attach_out:
Arend van Spriel3eacf862012-10-22 13:55:30 -07004244 brcmf_free_vif(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004245 return NULL;
4246}
4247
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004248void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004249{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004250 struct brcmf_cfg80211_vif *vif;
4251 struct brcmf_cfg80211_vif *tmp;
4252
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004253 wl_deinit_priv(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004254 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4255 brcmf_free_vif(vif);
4256 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004257}
4258
Arend van Spriel5b435de2011-10-05 13:19:03 +02004259static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004260brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004261{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004262 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02004263 __le32 roamtrigger[2];
4264 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02004265
4266 /*
4267 * Setup timeout if Beacons are lost and roam is
4268 * off to report link down
4269 */
4270 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004271 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004272 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004273 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004274 goto dongle_rom_out;
4275 }
4276 }
4277
4278 /*
4279 * Enable/Disable built-in roaming to allow supplicant
4280 * to take care of roaming
4281 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004282 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07004283 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004284 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004285 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004286 goto dongle_rom_out;
4287 }
4288
Arend van Sprielf588bc02011-10-12 20:51:22 +02004289 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4290 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004291 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004292 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004293 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004294 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004295 goto dongle_rom_out;
4296 }
4297
Arend van Sprielf588bc02011-10-12 20:51:22 +02004298 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4299 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004300 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004301 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004302 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004303 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004304 goto dongle_rom_out;
4305 }
4306
4307dongle_rom_out:
4308 return err;
4309}
4310
4311static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004312brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02004313 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004314{
4315 s32 err = 0;
4316
Arend van Sprielac24be62012-10-22 10:36:23 -07004317 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004318 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004319 if (err) {
4320 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004321 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004322 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004323 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004324 goto dongle_scantime_out;
4325 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004326 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004327 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004328 if (err) {
4329 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004330 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004331 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004332 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004333 goto dongle_scantime_out;
4334 }
4335
Arend van Sprielac24be62012-10-22 10:36:23 -07004336 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004337 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004338 if (err) {
4339 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004340 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004341 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004342 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004343 goto dongle_scantime_out;
4344 }
4345
4346dongle_scantime_out:
4347 return err;
4348}
4349
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004350static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004351{
Arend van Sprielac24be62012-10-22 10:36:23 -07004352 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004353 struct wiphy *wiphy;
4354 s32 phy_list;
4355 s8 phy;
4356 s32 err = 0;
4357
Hante Meulemanb87e2c42012-11-14 18:46:23 -08004358 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004359 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004360 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004361 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004362 return err;
4363 }
4364
Hante Meuleman3ba81372012-09-19 22:21:13 +02004365 phy = ((char *)&phy_list)[0];
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004366 brcmf_dbg(INFO, "%c phy\n", phy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004367 if (phy == 'n' || phy == 'a') {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004368 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004369 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4370 }
4371
4372 return err;
4373}
4374
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004375static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004376{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004377 return wl_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004378}
4379
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004380static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004381{
4382 struct net_device *ndev;
4383 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01004384 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004385 s32 power_mode;
4386 s32 err = 0;
4387
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004388 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004389 return err;
4390
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004391 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004392 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01004393 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004394
Hante Meuleman40a23292013-01-02 15:22:51 +01004395 /* make sure RF is ready for work */
4396 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
4397
4398 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
4399 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004400
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004401 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01004402 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004403 if (err)
4404 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004405 brcmf_dbg(INFO, "power save set to %s\n",
4406 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004407
Hante Meuleman40a23292013-01-02 15:22:51 +01004408 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004409 if (err)
4410 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07004411 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
4412 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01004413 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004414 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004415 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004416 if (err)
4417 goto default_conf_out;
4418
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004419 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01004420default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004421
4422 return err;
4423
4424}
4425
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004426static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004427{
Arend van Sprielc1179032012-10-22 13:55:33 -07004428 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004429
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004430 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004431}
4432
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004433static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004434{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004435 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07004436
Arend van Spriel5b435de2011-10-05 13:19:03 +02004437 /*
4438 * While going down, if associated with AP disassociate
4439 * from AP to save power
4440 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004441 if (check_vif_up(ifp->vif)) {
4442 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004443
4444 /* Make sure WPA_Supplicant receives all the event
4445 generated due to DISASSOC call to the fw to keep
4446 the state fw and WPA_Supplicant state consistent
4447 */
4448 brcmf_delay(500);
4449 }
4450
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004451 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07004452 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004453
Arend van Spriel5b435de2011-10-05 13:19:03 +02004454 return 0;
4455}
4456
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004457s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004458{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004459 struct brcmf_if *ifp = netdev_priv(ndev);
4460 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004461 s32 err = 0;
4462
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004463 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004464 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004465 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004466
4467 return err;
4468}
4469
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004470s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004471{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004472 struct brcmf_if *ifp = netdev_priv(ndev);
4473 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004474 s32 err = 0;
4475
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004476 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004477 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004478 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004479
4480 return err;
4481}
4482