blob: 0f170cb83c548d990fc43150888a2e213764a4ae [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
396 if (ch->flags & IEEE80211_CHAN_NO_HT40) {
397 chanspec |= WL_CHANSPEC_BW_20;
398 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
399 } else {
400 chanspec |= WL_CHANSPEC_BW_40;
401 if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
402 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
403 else
404 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
405 }
406 return chanspec;
407}
408
Arend van Spriel5b435de2011-10-05 13:19:03 +0200409static void convert_key_from_CPU(struct brcmf_wsec_key *key,
410 struct brcmf_wsec_key_le *key_le)
411{
412 key_le->index = cpu_to_le32(key->index);
413 key_le->len = cpu_to_le32(key->len);
414 key_le->algo = cpu_to_le32(key->algo);
415 key_le->flags = cpu_to_le32(key->flags);
416 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
417 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
418 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
419 memcpy(key_le->data, key->data, sizeof(key->data));
420 memcpy(key_le->ea, key->ea, sizeof(key->ea));
421}
422
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200423static int
Arend van Spriel2eaba7e2012-10-22 10:36:26 -0700424send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200425{
426 int err;
427 struct brcmf_wsec_key_le key_le;
428
429 convert_key_from_CPU(key, &key_le);
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200430
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700431 brcmf_netdev_wait_pend8021x(ndev);
432
Arend van Sprielac24be62012-10-22 10:36:23 -0700433 err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700434 sizeof(key_le));
Hante Meulemanf09d0c02012-09-27 14:17:48 +0200435
Arend van Spriel5b435de2011-10-05 13:19:03 +0200436 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100437 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200438 return err;
439}
440
441static s32
442brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
443 enum nl80211_iftype type, u32 *flags,
444 struct vif_params *params)
445{
Arend van Sprielc1179032012-10-22 13:55:33 -0700446 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100447 struct brcmf_cfg80211_vif *vif = ifp->vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200448 s32 infra = 0;
Hante Meuleman1a873342012-09-27 14:17:54 +0200449 s32 ap = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200450 s32 err = 0;
451
Arend van Sprield96b8012012-12-05 15:26:02 +0100452 brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200453
454 switch (type) {
455 case NL80211_IFTYPE_MONITOR:
456 case NL80211_IFTYPE_WDS:
Arend van Spriel57d6e912012-12-05 15:26:00 +0100457 brcmf_err("type (%d) : currently we do not support this type\n",
458 type);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459 return -EOPNOTSUPP;
460 case NL80211_IFTYPE_ADHOC:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100461 vif->mode = WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200462 infra = 0;
463 break;
464 case NL80211_IFTYPE_STATION:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100465 vif->mode = WL_MODE_BSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200466 infra = 1;
467 break;
Hante Meuleman1a873342012-09-27 14:17:54 +0200468 case NL80211_IFTYPE_AP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100469 vif->mode = WL_MODE_AP;
Hante Meuleman1a873342012-09-27 14:17:54 +0200470 ap = 1;
471 break;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200472 default:
473 err = -EINVAL;
474 goto done;
475 }
476
Hante Meuleman1a873342012-09-27 14:17:54 +0200477 if (ap) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100478 set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100479 brcmf_dbg(INFO, "IF Type = AP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200480 } else {
Arend van Spriel128ce3b2012-11-28 21:44:12 +0100481 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
Hante Meuleman1a873342012-09-27 14:17:54 +0200482 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100483 brcmf_err("WLC_SET_INFRA error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +0200484 err = -EAGAIN;
485 goto done;
486 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100487 brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
488 "Adhoc" : "Infra");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200489 }
Hante Meuleman1a873342012-09-27 14:17:54 +0200490 ndev->ieee80211_ptr->iftype = type;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200491
492done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100493 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200494
495 return err;
496}
497
Arend van Spriel5b435de2011-10-05 13:19:03 +0200498static void brcmf_set_mpc(struct net_device *ndev, int mpc)
499{
Arend van Sprielc1179032012-10-22 13:55:33 -0700500 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200501 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200502
Arend van Sprielce81e312012-10-22 13:55:37 -0700503 if (check_vif_up(ifp->vif)) {
Arend van Sprielc1179032012-10-22 13:55:33 -0700504 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200505 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100506 brcmf_err("fail to set mpc\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200507 return;
508 }
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100509 brcmf_dbg(INFO, "MPC : %d\n", mpc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200510 }
511}
512
Hante Meulemane756af52012-09-11 21:18:52 +0200513static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
514 struct cfg80211_scan_request *request)
515{
516 u32 n_ssids;
517 u32 n_channels;
518 s32 i;
519 s32 offset;
Arend van Spriel029591f2012-09-19 22:21:06 +0200520 u16 chanspec;
Hante Meulemane756af52012-09-11 21:18:52 +0200521 char *ptr;
Arend van Spriel029591f2012-09-19 22:21:06 +0200522 struct brcmf_ssid_le ssid_le;
Hante Meulemane756af52012-09-11 21:18:52 +0200523
Arend van Sprielba40d162012-10-22 13:55:38 -0700524 memset(params_le->bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200525 params_le->bss_type = DOT11_BSSTYPE_ANY;
526 params_le->scan_type = 0;
527 params_le->channel_num = 0;
528 params_le->nprobes = cpu_to_le32(-1);
529 params_le->active_time = cpu_to_le32(-1);
530 params_le->passive_time = cpu_to_le32(-1);
531 params_le->home_time = cpu_to_le32(-1);
532 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
533
534 /* if request is null exit so it will be all channel broadcast scan */
535 if (!request)
536 return;
537
538 n_ssids = request->n_ssids;
539 n_channels = request->n_channels;
540 /* Copy channel array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100541 brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
542 n_channels);
Hante Meulemane756af52012-09-11 21:18:52 +0200543 if (n_channels > 0) {
544 for (i = 0; i < n_channels; i++) {
Arend van Spriel6e186162012-10-22 10:36:22 -0700545 chanspec = channel_to_chanspec(request->channels[i]);
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100546 brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
547 request->channels[i]->hw_value, chanspec);
Arend van Spriel029591f2012-09-19 22:21:06 +0200548 params_le->channel_list[i] = cpu_to_le16(chanspec);
Hante Meulemane756af52012-09-11 21:18:52 +0200549 }
550 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100551 brcmf_dbg(SCAN, "Scanning all channels\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200552 }
553 /* Copy ssid array if applicable */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100554 brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200555 if (n_ssids > 0) {
556 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
557 n_channels * sizeof(u16);
558 offset = roundup(offset, sizeof(u32));
559 ptr = (char *)params_le + offset;
560 for (i = 0; i < n_ssids; i++) {
Arend van Spriel029591f2012-09-19 22:21:06 +0200561 memset(&ssid_le, 0, sizeof(ssid_le));
562 ssid_le.SSID_len =
563 cpu_to_le32(request->ssids[i].ssid_len);
564 memcpy(ssid_le.SSID, request->ssids[i].ssid,
565 request->ssids[i].ssid_len);
566 if (!ssid_le.SSID_len)
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100567 brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
Hante Meulemane756af52012-09-11 21:18:52 +0200568 else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100569 brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
570 i, ssid_le.SSID, ssid_le.SSID_len);
Arend van Spriel029591f2012-09-19 22:21:06 +0200571 memcpy(ptr, &ssid_le, sizeof(ssid_le));
572 ptr += sizeof(ssid_le);
Hante Meulemane756af52012-09-11 21:18:52 +0200573 }
574 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100575 brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
Hante Meulemane756af52012-09-11 21:18:52 +0200576 if ((request->ssids) && request->ssids->ssid_len) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100577 brcmf_dbg(SCAN, "SSID %s len=%d\n",
578 params_le->ssid_le.SSID,
579 request->ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200580 params_le->ssid_le.SSID_len =
581 cpu_to_le32(request->ssids->ssid_len);
582 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
583 request->ssids->ssid_len);
584 }
585 }
586 /* Adding mask to channel numbers */
587 params_le->channel_num =
588 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
589 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
590}
591
592static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200593brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
Hante Meulemane756af52012-09-11 21:18:52 +0200594 struct net_device *ndev,
595 bool aborted, bool fw_abort)
596{
597 struct brcmf_scan_params_le params_le;
598 struct cfg80211_scan_request *scan_request;
599 s32 err = 0;
600
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100601 brcmf_dbg(SCAN, "Enter\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200602
603 /* clear scan request, because the FW abort can cause a second call */
604 /* to this functon and might cause a double cfg80211_scan_done */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200605 scan_request = cfg->scan_request;
606 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200607
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200608 if (timer_pending(&cfg->escan_timeout))
609 del_timer_sync(&cfg->escan_timeout);
Hante Meulemane756af52012-09-11 21:18:52 +0200610
611 if (fw_abort) {
612 /* Do a scan abort to stop the driver's scan engine */
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100613 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200614 memset(&params_le, 0, sizeof(params_le));
Arend van Sprielba40d162012-10-22 13:55:38 -0700615 memset(params_le.bssid, 0xFF, ETH_ALEN);
Hante Meulemane756af52012-09-11 21:18:52 +0200616 params_le.bss_type = DOT11_BSSTYPE_ANY;
617 params_le.scan_type = 0;
618 params_le.channel_num = cpu_to_le32(1);
619 params_le.nprobes = cpu_to_le32(1);
620 params_le.active_time = cpu_to_le32(-1);
621 params_le.passive_time = cpu_to_le32(-1);
622 params_le.home_time = cpu_to_le32(-1);
623 /* Scan is aborted by setting channel_list[0] to -1 */
624 params_le.channel_list[0] = cpu_to_le16(-1);
625 /* E-Scan (or anyother type) can be aborted by SCAN */
Arend van Sprielac24be62012-10-22 10:36:23 -0700626 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
627 &params_le, sizeof(params_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200628 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100629 brcmf_err("Scan abort failed\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200630 }
Arend van Spriele5806072012-09-19 22:21:08 +0200631 /*
632 * e-scan can be initiated by scheduled scan
633 * which takes precedence.
634 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200635 if (cfg->sched_escan) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100636 brcmf_dbg(SCAN, "scheduled scan completed\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200637 cfg->sched_escan = false;
Arend van Spriele5806072012-09-19 22:21:08 +0200638 if (!aborted)
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200639 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
Arend van Spriele5806072012-09-19 22:21:08 +0200640 brcmf_set_mpc(ndev, 1);
641 } else if (scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100642 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
643 aborted ? "Aborted" : "Done");
Hante Meulemane756af52012-09-11 21:18:52 +0200644 cfg80211_scan_done(scan_request, aborted);
645 brcmf_set_mpc(ndev, 1);
646 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700647 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100648 brcmf_err("Scan complete while device not scanning\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200649 return -EPERM;
650 }
651
652 return err;
653}
654
655static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200656brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
Hante Meulemane756af52012-09-11 21:18:52 +0200657 struct cfg80211_scan_request *request, u16 action)
658{
659 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
660 offsetof(struct brcmf_escan_params_le, params_le);
661 struct brcmf_escan_params_le *params;
662 s32 err = 0;
663
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100664 brcmf_dbg(SCAN, "E-SCAN START\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200665
666 if (request != NULL) {
667 /* Allocate space for populating ssids in struct */
668 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
669
670 /* Allocate space for populating ssids in struct */
671 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
672 }
673
674 params = kzalloc(params_size, GFP_KERNEL);
675 if (!params) {
676 err = -ENOMEM;
677 goto exit;
678 }
679 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
680 brcmf_escan_prep(&params->params_le, request);
681 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
682 params->action = cpu_to_le16(action);
683 params->sync_id = cpu_to_le16(0x1234);
684
Arend van Sprielac24be62012-10-22 10:36:23 -0700685 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
686 params, params_size);
Hante Meulemane756af52012-09-11 21:18:52 +0200687 if (err) {
688 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100689 brcmf_dbg(INFO, "system busy : escan canceled\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200690 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100691 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200692 }
693
694 kfree(params);
695exit:
696 return err;
697}
698
699static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200700brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
Hante Meulemane756af52012-09-11 21:18:52 +0200701 struct net_device *ndev, struct cfg80211_scan_request *request)
702{
703 s32 err;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700704 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200705 struct brcmf_scan_results *results;
706
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100707 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200708 cfg->escan_info.ndev = ndev;
709 cfg->escan_info.wiphy = wiphy;
710 cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700711 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielac24be62012-10-22 10:36:23 -0700712 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700713 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200714 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100715 brcmf_err("error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200716 return err;
717 }
718 brcmf_set_mpc(ndev, 0);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200719 results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +0200720 results->version = 0;
721 results->count = 0;
722 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
723
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200724 err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
Hante Meulemane756af52012-09-11 21:18:52 +0200725 if (err)
726 brcmf_set_mpc(ndev, 1);
727 return err;
728}
729
730static s32
731brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
732 struct cfg80211_scan_request *request,
733 struct cfg80211_ssid *this_ssid)
734{
Arend van Sprielc1179032012-10-22 13:55:33 -0700735 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200736 struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
Hante Meulemane756af52012-09-11 21:18:52 +0200737 struct cfg80211_ssid *ssids;
Hante Meulemanf07998952012-11-05 16:22:13 -0800738 struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700739 u32 passive_scan;
Hante Meulemane756af52012-09-11 21:18:52 +0200740 bool escan_req;
741 bool spec_scan;
742 s32 err;
743 u32 SSID_len;
744
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100745 brcmf_dbg(SCAN, "START ESCAN\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200746
Arend van Sprielc1179032012-10-22 13:55:33 -0700747 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100748 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200749 return -EAGAIN;
750 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700751 if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100752 brcmf_err("Scanning being aborted: status (%lu)\n",
753 cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200754 return -EAGAIN;
755 }
Arend van Sprielc1179032012-10-22 13:55:33 -0700756 if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100757 brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
Hante Meulemane756af52012-09-11 21:18:52 +0200758 return -EAGAIN;
759 }
760
761 /* Arm scan timeout timer */
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200762 mod_timer(&cfg->escan_timeout, jiffies +
Hante Meulemane756af52012-09-11 21:18:52 +0200763 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
764
765 escan_req = false;
766 if (request) {
767 /* scan bss */
768 ssids = request->ssids;
769 escan_req = true;
770 } else {
771 /* scan in ibss */
772 /* we don't do escan in ibss */
773 ssids = this_ssid;
774 }
775
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200776 cfg->scan_request = request;
Arend van Sprielc1179032012-10-22 13:55:33 -0700777 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Hante Meulemane756af52012-09-11 21:18:52 +0200778 if (escan_req) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200779 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriel2cb941c2012-11-05 16:22:10 -0800780 if (err)
Hante Meulemane756af52012-09-11 21:18:52 +0200781 goto scan_out;
782 } else {
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100783 brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
784 ssids->ssid, ssids->ssid_len);
Hante Meulemane756af52012-09-11 21:18:52 +0200785 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
786 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
787 sr->ssid_le.SSID_len = cpu_to_le32(0);
788 spec_scan = false;
789 if (SSID_len) {
790 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
791 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
792 spec_scan = true;
793 } else
Arend van Spriel4e8a0082012-12-05 15:26:03 +0100794 brcmf_dbg(SCAN, "Broadcast scan\n");
Hante Meulemane756af52012-09-11 21:18:52 +0200795
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700796 passive_scan = cfg->active_scan ? 0 : 1;
Arend van Sprielc1179032012-10-22 13:55:33 -0700797 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -0700798 passive_scan);
Hante Meulemane756af52012-09-11 21:18:52 +0200799 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100800 brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200801 goto scan_out;
802 }
803 brcmf_set_mpc(ndev, 0);
Arend van Sprielc1179032012-10-22 13:55:33 -0700804 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
Arend van Sprielac24be62012-10-22 10:36:23 -0700805 &sr->ssid_le, sizeof(sr->ssid_le));
Hante Meulemane756af52012-09-11 21:18:52 +0200806 if (err) {
807 if (err == -EBUSY)
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100808 brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
809 sr->ssid_le.SSID);
Hante Meulemane756af52012-09-11 21:18:52 +0200810 else
Arend van Spriel57d6e912012-12-05 15:26:00 +0100811 brcmf_err("WLC_SCAN error (%d)\n", err);
Hante Meulemane756af52012-09-11 21:18:52 +0200812
813 brcmf_set_mpc(ndev, 1);
814 goto scan_out;
815 }
816 }
817
818 return 0;
819
820scan_out:
Arend van Sprielc1179032012-10-22 13:55:33 -0700821 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200822 if (timer_pending(&cfg->escan_timeout))
823 del_timer_sync(&cfg->escan_timeout);
824 cfg->scan_request = NULL;
Hante Meulemane756af52012-09-11 21:18:52 +0200825 return err;
826}
827
Arend van Spriel5b435de2011-10-05 13:19:03 +0200828static s32
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700829brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200830{
Johannes Bergfd014282012-06-18 19:17:03 +0200831 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200832 s32 err = 0;
833
Arend van Sprield96b8012012-12-05 15:26:02 +0100834 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200835
Arend van Sprielce81e312012-10-22 13:55:37 -0700836 if (!check_vif_up(container_of(request->wdev,
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700837 struct brcmf_cfg80211_vif, wdev)))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200838 return -EIO;
839
Hante Meulemanf07998952012-11-05 16:22:13 -0800840 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
Hante Meulemane756af52012-09-11 21:18:52 +0200841
Arend van Spriel5b435de2011-10-05 13:19:03 +0200842 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100843 brcmf_err("scan error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200844
Arend van Sprield96b8012012-12-05 15:26:02 +0100845 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200846 return err;
847}
848
849static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
850{
851 s32 err = 0;
852
Arend van Sprielac24be62012-10-22 10:36:23 -0700853 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
854 rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200855 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100856 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200857
858 return err;
859}
860
861static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
862{
863 s32 err = 0;
864
Arend van Sprielac24be62012-10-22 10:36:23 -0700865 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
866 frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200867 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100868 brcmf_err("Error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200869
870 return err;
871}
872
873static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
874{
875 s32 err = 0;
Hante Meulemanb87e2c42012-11-14 18:46:23 -0800876 u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200877
Arend van Sprielac24be62012-10-22 10:36:23 -0700878 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200879 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +0100880 brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200881 return err;
882 }
883 return err;
884}
885
886static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
887{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200888 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
889 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700890 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200891 s32 err = 0;
892
Arend van Sprield96b8012012-12-05 15:26:02 +0100893 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -0700894 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200895 return -EIO;
896
897 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200898 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
899 cfg->conf->rts_threshold = wiphy->rts_threshold;
900 err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200901 if (!err)
902 goto done;
903 }
904 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200905 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
906 cfg->conf->frag_threshold = wiphy->frag_threshold;
907 err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200908 if (!err)
909 goto done;
910 }
911 if (changed & WIPHY_PARAM_RETRY_LONG
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200912 && (cfg->conf->retry_long != wiphy->retry_long)) {
913 cfg->conf->retry_long = wiphy->retry_long;
914 err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200915 if (!err)
916 goto done;
917 }
918 if (changed & WIPHY_PARAM_RETRY_SHORT
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200919 && (cfg->conf->retry_short != wiphy->retry_short)) {
920 cfg->conf->retry_short = wiphy->retry_short;
921 err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200922 if (!err)
923 goto done;
924 }
925
926done:
Arend van Sprield96b8012012-12-05 15:26:02 +0100927 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200928 return err;
929}
930
Arend van Spriel5b435de2011-10-05 13:19:03 +0200931static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
932{
933 memset(prof, 0, sizeof(*prof));
934}
935
936static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
937 size_t *join_params_size)
938{
939 u16 chanspec = 0;
940
941 if (ch != 0) {
942 if (ch <= CH_MAX_2G_CHANNEL)
943 chanspec |= WL_CHANSPEC_BAND_2G;
944 else
945 chanspec |= WL_CHANSPEC_BAND_5G;
946
947 chanspec |= WL_CHANSPEC_BW_20;
948 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
949
950 *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
951 sizeof(u16);
952
953 chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
954 join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
955 join_params->params_le.chanspec_num = cpu_to_le32(1);
956
Arend van Spriel16886732012-12-05 15:26:04 +0100957 brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200958 }
959}
960
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100961static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200962{
Arend van Spriel5b435de2011-10-05 13:19:03 +0200963 s32 err = 0;
964
Arend van Sprield96b8012012-12-05 15:26:02 +0100965 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200966
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100967 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
Arend van Spriel647c9ae2012-12-05 15:26:01 +0100968 brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100969 err = brcmf_fil_cmd_data_set(vif->ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -0700970 BRCMF_C_DISASSOC, NULL, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200971 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +0100972 brcmf_err("WLC_DISASSOC failed (%d)\n", err);
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100973 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200974 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +0100975 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +0100976 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200977}
978
979static s32
980brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
981 struct cfg80211_ibss_params *params)
982{
Arend van Spriel27a68fe2012-09-27 14:17:55 +0200983 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -0700984 struct brcmf_if *ifp = netdev_priv(ndev);
985 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200986 struct brcmf_join_params join_params;
987 size_t join_params_size = 0;
988 s32 err = 0;
989 s32 wsec = 0;
990 s32 bcnprd;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200991
Arend van Sprield96b8012012-12-05 15:26:02 +0100992 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -0700993 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +0200994 return -EIO;
995
996 if (params->ssid)
Arend van Spriel16886732012-12-05 15:26:04 +0100997 brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200998 else {
Arend van Spriel16886732012-12-05 15:26:04 +0100999 brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001000 return -EOPNOTSUPP;
1001 }
1002
Arend van Sprielc1179032012-10-22 13:55:33 -07001003 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001004
1005 if (params->bssid)
Arend van Spriel16886732012-12-05 15:26:04 +01001006 brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001007 else
Arend van Spriel16886732012-12-05 15:26:04 +01001008 brcmf_dbg(CONN, "No BSSID specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001009
Johannes Berg683b6d32012-11-08 21:25:48 +01001010 if (params->chandef.chan)
Arend van Spriel16886732012-12-05 15:26:04 +01001011 brcmf_dbg(CONN, "channel: %d\n",
1012 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001013 else
Arend van Spriel16886732012-12-05 15:26:04 +01001014 brcmf_dbg(CONN, "no channel specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001015
1016 if (params->channel_fixed)
Arend van Spriel16886732012-12-05 15:26:04 +01001017 brcmf_dbg(CONN, "fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001018 else
Arend van Spriel16886732012-12-05 15:26:04 +01001019 brcmf_dbg(CONN, "no fixed channel required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001020
1021 if (params->ie && params->ie_len)
Arend van Spriel16886732012-12-05 15:26:04 +01001022 brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001023 else
Arend van Spriel16886732012-12-05 15:26:04 +01001024 brcmf_dbg(CONN, "no ie specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001025
1026 if (params->beacon_interval)
Arend van Spriel16886732012-12-05 15:26:04 +01001027 brcmf_dbg(CONN, "beacon interval: %d\n",
1028 params->beacon_interval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001029 else
Arend van Spriel16886732012-12-05 15:26:04 +01001030 brcmf_dbg(CONN, "no beacon interval specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001031
1032 if (params->basic_rates)
Arend van Spriel16886732012-12-05 15:26:04 +01001033 brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001034 else
Arend van Spriel16886732012-12-05 15:26:04 +01001035 brcmf_dbg(CONN, "no basic rates specified\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001036
1037 if (params->privacy)
Arend van Spriel16886732012-12-05 15:26:04 +01001038 brcmf_dbg(CONN, "privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001039 else
Arend van Spriel16886732012-12-05 15:26:04 +01001040 brcmf_dbg(CONN, "no privacy required\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001041
1042 /* Configure Privacy for starter */
1043 if (params->privacy)
1044 wsec |= WEP_ENABLED;
1045
Arend van Sprielc1179032012-10-22 13:55:33 -07001046 err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001047 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001048 brcmf_err("wsec failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001049 goto done;
1050 }
1051
1052 /* Configure Beacon Interval for starter */
1053 if (params->beacon_interval)
1054 bcnprd = params->beacon_interval;
1055 else
1056 bcnprd = 100;
1057
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001058 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001059 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001060 brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001061 goto done;
1062 }
1063
1064 /* Configure required join parameter */
1065 memset(&join_params, 0, sizeof(struct brcmf_join_params));
1066
1067 /* SSID */
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001068 profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
1069 memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
1070 memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
1071 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001072 join_params_size = sizeof(join_params.ssid_le);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001073
1074 /* BSSID */
1075 if (params->bssid) {
1076 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
1077 join_params_size = sizeof(join_params.ssid_le) +
1078 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001079 memcpy(profile->bssid, params->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001080 } else {
Arend van Sprielba40d162012-10-22 13:55:38 -07001081 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001082 memset(profile->bssid, 0, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001083 }
1084
Arend van Spriel5b435de2011-10-05 13:19:03 +02001085 /* Channel */
Johannes Berg683b6d32012-11-08 21:25:48 +01001086 if (params->chandef.chan) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001087 u32 target_channel;
1088
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001089 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001090 ieee80211_frequency_to_channel(
Johannes Berg683b6d32012-11-08 21:25:48 +01001091 params->chandef.chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001092 if (params->channel_fixed) {
1093 /* adding chanspec */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001094 brcmf_ch_to_chanspec(cfg->channel,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001095 &join_params, &join_params_size);
1096 }
1097
1098 /* set channel for starter */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001099 target_channel = cfg->channel;
Hante Meulemanb87e2c42012-11-14 18:46:23 -08001100 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001101 target_channel);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001102 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001103 brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001104 goto done;
1105 }
1106 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001107 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001108
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001109 cfg->ibss_starter = false;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001110
1111
Arend van Sprielc1179032012-10-22 13:55:33 -07001112 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001113 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001114 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001115 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001116 goto done;
1117 }
1118
1119done:
1120 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001121 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001122 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001123 return err;
1124}
1125
1126static s32
1127brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1128{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001129 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001130 s32 err = 0;
1131
Arend van Sprield96b8012012-12-05 15:26:02 +01001132 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001133 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001134 return -EIO;
1135
Arend van Spriel903e0ee2012-11-28 21:44:11 +01001136 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001137
Arend van Sprield96b8012012-12-05 15:26:02 +01001138 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001139
1140 return err;
1141}
1142
1143static s32 brcmf_set_wpa_version(struct net_device *ndev,
1144 struct cfg80211_connect_params *sme)
1145{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001146 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001147 struct brcmf_cfg80211_security *sec;
1148 s32 val = 0;
1149 s32 err = 0;
1150
1151 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1152 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1153 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1154 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1155 else
1156 val = WPA_AUTH_DISABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001157 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001158 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001159 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001160 brcmf_err("set wpa_auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001161 return err;
1162 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001163 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001164 sec->wpa_versions = sme->crypto.wpa_versions;
1165 return err;
1166}
1167
1168static s32 brcmf_set_auth_type(struct net_device *ndev,
1169 struct cfg80211_connect_params *sme)
1170{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001171 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001172 struct brcmf_cfg80211_security *sec;
1173 s32 val = 0;
1174 s32 err = 0;
1175
1176 switch (sme->auth_type) {
1177 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1178 val = 0;
Arend van Spriel16886732012-12-05 15:26:04 +01001179 brcmf_dbg(CONN, "open system\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001180 break;
1181 case NL80211_AUTHTYPE_SHARED_KEY:
1182 val = 1;
Arend van Spriel16886732012-12-05 15:26:04 +01001183 brcmf_dbg(CONN, "shared key\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001184 break;
1185 case NL80211_AUTHTYPE_AUTOMATIC:
1186 val = 2;
Arend van Spriel16886732012-12-05 15:26:04 +01001187 brcmf_dbg(CONN, "automatic\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001188 break;
1189 case NL80211_AUTHTYPE_NETWORK_EAP:
Arend van Spriel16886732012-12-05 15:26:04 +01001190 brcmf_dbg(CONN, "network eap\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001191 default:
1192 val = 2;
Arend van Spriel57d6e912012-12-05 15:26:00 +01001193 brcmf_err("invalid auth type (%d)\n", sme->auth_type);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001194 break;
1195 }
1196
Arend van Sprielac24be62012-10-22 10:36:23 -07001197 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001198 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001199 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001200 return err;
1201 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001202 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001203 sec->auth_type = sme->auth_type;
1204 return err;
1205}
1206
1207static s32
1208brcmf_set_set_cipher(struct net_device *ndev,
1209 struct cfg80211_connect_params *sme)
1210{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001211 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001212 struct brcmf_cfg80211_security *sec;
1213 s32 pval = 0;
1214 s32 gval = 0;
1215 s32 err = 0;
1216
1217 if (sme->crypto.n_ciphers_pairwise) {
1218 switch (sme->crypto.ciphers_pairwise[0]) {
1219 case WLAN_CIPHER_SUITE_WEP40:
1220 case WLAN_CIPHER_SUITE_WEP104:
1221 pval = WEP_ENABLED;
1222 break;
1223 case WLAN_CIPHER_SUITE_TKIP:
1224 pval = TKIP_ENABLED;
1225 break;
1226 case WLAN_CIPHER_SUITE_CCMP:
1227 pval = AES_ENABLED;
1228 break;
1229 case WLAN_CIPHER_SUITE_AES_CMAC:
1230 pval = AES_ENABLED;
1231 break;
1232 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001233 brcmf_err("invalid cipher pairwise (%d)\n",
1234 sme->crypto.ciphers_pairwise[0]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001235 return -EINVAL;
1236 }
1237 }
1238 if (sme->crypto.cipher_group) {
1239 switch (sme->crypto.cipher_group) {
1240 case WLAN_CIPHER_SUITE_WEP40:
1241 case WLAN_CIPHER_SUITE_WEP104:
1242 gval = WEP_ENABLED;
1243 break;
1244 case WLAN_CIPHER_SUITE_TKIP:
1245 gval = TKIP_ENABLED;
1246 break;
1247 case WLAN_CIPHER_SUITE_CCMP:
1248 gval = AES_ENABLED;
1249 break;
1250 case WLAN_CIPHER_SUITE_AES_CMAC:
1251 gval = AES_ENABLED;
1252 break;
1253 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001254 brcmf_err("invalid cipher group (%d)\n",
1255 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001256 return -EINVAL;
1257 }
1258 }
1259
Arend van Spriel16886732012-12-05 15:26:04 +01001260 brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
Arend van Sprielac24be62012-10-22 10:36:23 -07001261 err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001262 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001263 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001264 return err;
1265 }
1266
Arend van Spriel06bb1232012-09-27 14:17:56 +02001267 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001268 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1269 sec->cipher_group = sme->crypto.cipher_group;
1270
1271 return err;
1272}
1273
1274static s32
1275brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1276{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001277 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001278 struct brcmf_cfg80211_security *sec;
1279 s32 val = 0;
1280 s32 err = 0;
1281
1282 if (sme->crypto.n_akm_suites) {
Arend van Sprielac24be62012-10-22 10:36:23 -07001283 err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
1284 "wpa_auth", &val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001286 brcmf_err("could not get wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001287 return err;
1288 }
1289 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1290 switch (sme->crypto.akm_suites[0]) {
1291 case WLAN_AKM_SUITE_8021X:
1292 val = WPA_AUTH_UNSPECIFIED;
1293 break;
1294 case WLAN_AKM_SUITE_PSK:
1295 val = WPA_AUTH_PSK;
1296 break;
1297 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001298 brcmf_err("invalid cipher group (%d)\n",
1299 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001300 return -EINVAL;
1301 }
1302 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1303 switch (sme->crypto.akm_suites[0]) {
1304 case WLAN_AKM_SUITE_8021X:
1305 val = WPA2_AUTH_UNSPECIFIED;
1306 break;
1307 case WLAN_AKM_SUITE_PSK:
1308 val = WPA2_AUTH_PSK;
1309 break;
1310 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001311 brcmf_err("invalid cipher group (%d)\n",
1312 sme->crypto.cipher_group);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001313 return -EINVAL;
1314 }
1315 }
1316
Arend van Spriel16886732012-12-05 15:26:04 +01001317 brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
Arend van Sprielac24be62012-10-22 10:36:23 -07001318 err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
1319 "wpa_auth", val);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001320 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001321 brcmf_err("could not set wpa_auth (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001322 return err;
1323 }
1324 }
Arend van Spriel06bb1232012-09-27 14:17:56 +02001325 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001326 sec->wpa_auth = sme->crypto.akm_suites[0];
1327
1328 return err;
1329}
1330
1331static s32
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001332brcmf_set_sharedkey(struct net_device *ndev,
1333 struct cfg80211_connect_params *sme)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001334{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07001335 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001336 struct brcmf_cfg80211_security *sec;
1337 struct brcmf_wsec_key key;
1338 s32 val;
1339 s32 err = 0;
1340
Arend van Spriel16886732012-12-05 15:26:04 +01001341 brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001342
Roland Vossena718e2f2011-10-12 20:51:24 +02001343 if (sme->key_len == 0)
1344 return 0;
1345
Arend van Spriel06bb1232012-09-27 14:17:56 +02001346 sec = &profile->sec;
Arend van Spriel16886732012-12-05 15:26:04 +01001347 brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
1348 sec->wpa_versions, sec->cipher_pairwise);
Roland Vossena718e2f2011-10-12 20:51:24 +02001349
1350 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1351 return 0;
1352
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001353 if (!(sec->cipher_pairwise &
1354 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
1355 return 0;
Roland Vossena718e2f2011-10-12 20:51:24 +02001356
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001357 memset(&key, 0, sizeof(key));
1358 key.len = (u32) sme->key_len;
1359 key.index = (u32) sme->key_idx;
1360 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001361 brcmf_err("Too long key length (%u)\n", key.len);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001362 return -EINVAL;
1363 }
1364 memcpy(key.data, sme->key, key.len);
1365 key.flags = BRCMF_PRIMARY_KEY;
1366 switch (sec->cipher_pairwise) {
1367 case WLAN_CIPHER_SUITE_WEP40:
1368 key.algo = CRYPTO_ALGO_WEP1;
1369 break;
1370 case WLAN_CIPHER_SUITE_WEP104:
1371 key.algo = CRYPTO_ALGO_WEP128;
1372 break;
1373 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001374 brcmf_err("Invalid algorithm (%d)\n",
1375 sme->crypto.ciphers_pairwise[0]);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001376 return -EINVAL;
1377 }
1378 /* Set the new key/index */
Arend van Spriel16886732012-12-05 15:26:04 +01001379 brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
1380 key.len, key.index, key.algo);
1381 brcmf_dbg(CONN, "key \"%s\"\n", key.data);
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001382 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001383 if (err)
1384 return err;
1385
1386 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
Arend van Spriel16886732012-12-05 15:26:04 +01001387 brcmf_dbg(CONN, "set auth_type to shared key\n");
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001388 val = WL_AUTH_SHARED_KEY; /* shared key */
Arend van Sprielac24be62012-10-22 10:36:23 -07001389 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001390 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001391 brcmf_err("set auth failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001392 }
1393 return err;
1394}
1395
1396static s32
1397brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1398 struct cfg80211_connect_params *sme)
1399{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001400 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001401 struct brcmf_if *ifp = netdev_priv(ndev);
1402 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001403 struct ieee80211_channel *chan = sme->channel;
1404 struct brcmf_join_params join_params;
1405 size_t join_params_size;
1406 struct brcmf_ssid ssid;
1407
1408 s32 err = 0;
1409
Arend van Sprield96b8012012-12-05 15:26:02 +01001410 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001411 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001412 return -EIO;
1413
1414 if (!sme->ssid) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001415 brcmf_err("Invalid ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001416 return -EOPNOTSUPP;
1417 }
1418
Arend van Sprielc1179032012-10-22 13:55:33 -07001419 set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001420
1421 if (chan) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001422 cfg->channel =
Arend van Spriel5b435de2011-10-05 13:19:03 +02001423 ieee80211_frequency_to_channel(chan->center_freq);
Arend van Spriel16886732012-12-05 15:26:04 +01001424 brcmf_dbg(CONN, "channel (%d), center_req (%d)\n",
1425 cfg->channel, chan->center_freq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001426 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001427 cfg->channel = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001428
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001429 brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430
1431 err = brcmf_set_wpa_version(ndev, sme);
1432 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001433 brcmf_err("wl_set_wpa_version failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001434 goto done;
1435 }
1436
1437 err = brcmf_set_auth_type(ndev, sme);
1438 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001439 brcmf_err("wl_set_auth_type failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001440 goto done;
1441 }
1442
1443 err = brcmf_set_set_cipher(ndev, sme);
1444 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001445 brcmf_err("wl_set_set_cipher failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001446 goto done;
1447 }
1448
1449 err = brcmf_set_key_mgmt(ndev, sme);
1450 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001451 brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452 goto done;
1453 }
1454
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001455 err = brcmf_set_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001456 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001457 brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001458 goto done;
1459 }
1460
1461 memset(&join_params, 0, sizeof(join_params));
1462 join_params_size = sizeof(join_params.ssid_le);
1463
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02001464 profile->ssid.SSID_len = min_t(u32,
1465 sizeof(ssid.SSID), (u32)sme->ssid_len);
1466 memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
1467 memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
1468 join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001469
Arend van Sprielba40d162012-10-22 13:55:38 -07001470 memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001471
1472 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
Arend van Spriel16886732012-12-05 15:26:04 +01001473 brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
1474 ssid.SSID, ssid.SSID_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001475
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001476 brcmf_ch_to_chanspec(cfg->channel,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001477 &join_params, &join_params_size);
Arend van Sprielc1179032012-10-22 13:55:33 -07001478 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001479 &join_params, join_params_size);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001480 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001481 brcmf_err("WLC_SET_SSID failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001482
1483done:
1484 if (err)
Arend van Sprielc1179032012-10-22 13:55:33 -07001485 clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01001486 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001487 return err;
1488}
1489
1490static s32
1491brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1492 u16 reason_code)
1493{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001494 struct brcmf_if *ifp = netdev_priv(ndev);
1495 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001496 struct brcmf_scb_val_le scbval;
1497 s32 err = 0;
1498
Arend van Sprield96b8012012-12-05 15:26:02 +01001499 brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
Arend van Sprielce81e312012-10-22 13:55:37 -07001500 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001501 return -EIO;
1502
Arend van Sprielc1179032012-10-22 13:55:33 -07001503 clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001504
Arend van Spriel06bb1232012-09-27 14:17:56 +02001505 memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001506 scbval.val = cpu_to_le32(reason_code);
Arend van Sprielc1179032012-10-22 13:55:33 -07001507 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
Arend van Sprielac24be62012-10-22 10:36:23 -07001508 &scbval, sizeof(scbval));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001509 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001510 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001511
Arend van Sprield96b8012012-12-05 15:26:02 +01001512 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001513 return err;
1514}
1515
1516static s32
Johannes Bergc8442112012-10-24 10:17:18 +02001517brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001518 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001519{
1520
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001521 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001522 struct net_device *ndev = cfg_to_ndev(cfg);
1523 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001524 u16 txpwrmw;
1525 s32 err = 0;
1526 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001527 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001528
Arend van Sprield96b8012012-12-05 15:26:02 +01001529 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001530 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001531 return -EIO;
1532
1533 switch (type) {
1534 case NL80211_TX_POWER_AUTOMATIC:
1535 break;
1536 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001537 case NL80211_TX_POWER_FIXED:
1538 if (dbm < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001539 brcmf_err("TX_POWER_FIXED - dbm is negative\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001540 err = -EINVAL;
1541 goto done;
1542 }
1543 break;
1544 }
1545 /* Make sure radio is off or on as far as software is concerned */
1546 disable = WL_RADIO_SW_DISABLE << 16;
Arend van Sprielac24be62012-10-22 10:36:23 -07001547 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001548 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001549 brcmf_err("WLC_SET_RADIO error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001550
1551 if (dbm > 0xffff)
1552 txpwrmw = 0xffff;
1553 else
1554 txpwrmw = (u16) dbm;
Arend van Sprielac24be62012-10-22 10:36:23 -07001555 err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
1556 (s32)brcmf_mw_to_qdbm(txpwrmw));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001557 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001558 brcmf_err("qtxpower error (%d)\n", err);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001559 cfg->conf->tx_power = dbm;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001560
1561done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001562 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001563 return err;
1564}
1565
Johannes Bergc8442112012-10-24 10:17:18 +02001566static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
1567 struct wireless_dev *wdev,
1568 s32 *dbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001569{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001570 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001571 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001572 s32 txpwrdbm;
1573 u8 result;
1574 s32 err = 0;
1575
Arend van Sprield96b8012012-12-05 15:26:02 +01001576 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001577 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001578 return -EIO;
1579
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001580 err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001581 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001582 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001583 goto done;
1584 }
1585
1586 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001587 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001588
1589done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001590 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001591 return err;
1592}
1593
1594static s32
1595brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1596 u8 key_idx, bool unicast, bool multicast)
1597{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001598 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599 u32 index;
1600 u32 wsec;
1601 s32 err = 0;
1602
Arend van Sprield96b8012012-12-05 15:26:02 +01001603 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001604 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001605 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001606 return -EIO;
1607
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001608 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001609 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001610 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001611 goto done;
1612 }
1613
1614 if (wsec & WEP_ENABLED) {
1615 /* Just select a new current key */
1616 index = key_idx;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001617 err = brcmf_fil_cmd_int_set(ifp,
Arend van Sprielac24be62012-10-22 10:36:23 -07001618 BRCMF_C_SET_KEY_PRIMARY, index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001619 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001620 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001621 }
1622done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001623 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001624 return err;
1625}
1626
1627static s32
1628brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1629 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1630{
1631 struct brcmf_wsec_key key;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001632 s32 err = 0;
1633
1634 memset(&key, 0, sizeof(key));
1635 key.index = (u32) key_idx;
1636 /* Instead of bcast for ea address for default wep keys,
1637 driver needs it to be Null */
1638 if (!is_multicast_ether_addr(mac_addr))
1639 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1640 key.len = (u32) params->key_len;
1641 /* check for key index change */
1642 if (key.len == 0) {
1643 /* key delete */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001644 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001645 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001646 brcmf_err("key delete error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001647 } else {
1648 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001649 brcmf_err("Invalid key length (%d)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001650 return -EINVAL;
1651 }
1652
Arend van Spriel16886732012-12-05 15:26:04 +01001653 brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001654 memcpy(key.data, params->key, key.len);
1655
1656 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1657 u8 keybuf[8];
1658 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1659 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1660 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1661 }
1662
1663 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1664 if (params->seq && params->seq_len == 6) {
1665 /* rx iv */
1666 u8 *ivptr;
1667 ivptr = (u8 *) params->seq;
1668 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1669 (ivptr[3] << 8) | ivptr[2];
1670 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1671 key.iv_initialized = true;
1672 }
1673
1674 switch (params->cipher) {
1675 case WLAN_CIPHER_SUITE_WEP40:
1676 key.algo = CRYPTO_ALGO_WEP1;
Arend van Spriel16886732012-12-05 15:26:04 +01001677 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001678 break;
1679 case WLAN_CIPHER_SUITE_WEP104:
1680 key.algo = CRYPTO_ALGO_WEP128;
Arend van Spriel16886732012-12-05 15:26:04 +01001681 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001682 break;
1683 case WLAN_CIPHER_SUITE_TKIP:
1684 key.algo = CRYPTO_ALGO_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001685 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001686 break;
1687 case WLAN_CIPHER_SUITE_AES_CMAC:
1688 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001689 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001690 break;
1691 case WLAN_CIPHER_SUITE_CCMP:
1692 key.algo = CRYPTO_ALGO_AES_CCM;
Arend van Spriel16886732012-12-05 15:26:04 +01001693 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001694 break;
1695 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001696 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001697 return -EINVAL;
1698 }
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001699 err = send_key_to_dongle(ndev, &key);
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001700 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01001701 brcmf_err("wsec_key error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001702 }
1703 return err;
1704}
1705
1706static s32
1707brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1708 u8 key_idx, bool pairwise, const u8 *mac_addr,
1709 struct key_params *params)
1710{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001711 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001712 struct brcmf_wsec_key key;
1713 s32 val;
1714 s32 wsec;
1715 s32 err = 0;
1716 u8 keybuf[8];
1717
Arend van Sprield96b8012012-12-05 15:26:02 +01001718 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001719 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001720 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001721 return -EIO;
1722
1723 if (mac_addr) {
Arend van Sprield96b8012012-12-05 15:26:02 +01001724 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001725 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1726 }
1727 memset(&key, 0, sizeof(key));
1728
1729 key.len = (u32) params->key_len;
1730 key.index = (u32) key_idx;
1731
1732 if (key.len > sizeof(key.data)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001733 brcmf_err("Too long key length (%u)\n", key.len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001734 err = -EINVAL;
1735 goto done;
1736 }
1737 memcpy(key.data, params->key, key.len);
1738
1739 key.flags = BRCMF_PRIMARY_KEY;
1740 switch (params->cipher) {
1741 case WLAN_CIPHER_SUITE_WEP40:
1742 key.algo = CRYPTO_ALGO_WEP1;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001743 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001744 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001745 break;
1746 case WLAN_CIPHER_SUITE_WEP104:
1747 key.algo = CRYPTO_ALGO_WEP128;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001748 val = WEP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001749 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001750 break;
1751 case WLAN_CIPHER_SUITE_TKIP:
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001752 if (ifp->vif->mode != WL_MODE_AP) {
Arend van Spriel16886732012-12-05 15:26:04 +01001753 brcmf_dbg(CONN, "Swapping key\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02001754 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1755 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1756 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1757 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001758 key.algo = CRYPTO_ALGO_TKIP;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001759 val = TKIP_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001760 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001761 break;
1762 case WLAN_CIPHER_SUITE_AES_CMAC:
1763 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001764 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001765 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001766 break;
1767 case WLAN_CIPHER_SUITE_CCMP:
1768 key.algo = CRYPTO_ALGO_AES_CCM;
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001769 val = AES_ENABLED;
Arend van Spriel16886732012-12-05 15:26:04 +01001770 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001771 break;
1772 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001773 brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001774 err = -EINVAL;
1775 goto done;
1776 }
1777
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001778 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001779 if (err)
1780 goto done;
1781
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001782 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001783 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001784 brcmf_err("get wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001785 goto done;
1786 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001787 wsec |= val;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001788 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001789 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001790 brcmf_err("set wsec error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001791 goto done;
1792 }
1793
Arend van Spriel5b435de2011-10-05 13:19:03 +02001794done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001795 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001796 return err;
1797}
1798
1799static s32
1800brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1801 u8 key_idx, bool pairwise, const u8 *mac_addr)
1802{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001803 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001804 struct brcmf_wsec_key key;
1805 s32 err = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001806
Arend van Sprield96b8012012-12-05 15:26:02 +01001807 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07001808 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001809 return -EIO;
1810
Hante Meuleman256c3742012-11-05 16:22:28 -08001811 if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
1812 /* we ignore this key index in this case */
Arend van Spriel57d6e912012-12-05 15:26:00 +01001813 brcmf_err("invalid key index (%d)\n", key_idx);
Hante Meuleman256c3742012-11-05 16:22:28 -08001814 return -EINVAL;
1815 }
1816
Arend van Spriel5b435de2011-10-05 13:19:03 +02001817 memset(&key, 0, sizeof(key));
1818
1819 key.index = (u32) key_idx;
1820 key.flags = BRCMF_PRIMARY_KEY;
1821 key.algo = CRYPTO_ALGO_OFF;
1822
Arend van Spriel16886732012-12-05 15:26:04 +01001823 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001824
1825 /* Set the new key/index */
Arend van Spriel2eaba7e2012-10-22 10:36:26 -07001826 err = send_key_to_dongle(ndev, &key);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001827
Arend van Sprield96b8012012-12-05 15:26:02 +01001828 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001829 return err;
1830}
1831
1832static s32
1833brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1834 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
1835 void (*callback) (void *cookie, struct key_params * params))
1836{
1837 struct key_params params;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001838 struct brcmf_if *ifp = netdev_priv(ndev);
1839 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001840 struct brcmf_cfg80211_security *sec;
1841 s32 wsec;
1842 s32 err = 0;
1843
Arend van Sprield96b8012012-12-05 15:26:02 +01001844 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel16886732012-12-05 15:26:04 +01001845 brcmf_dbg(CONN, "key index (%d)\n", key_idx);
Arend van Sprielce81e312012-10-22 13:55:37 -07001846 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001847 return -EIO;
1848
1849 memset(&params, 0, sizeof(params));
1850
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001851 err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001852 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001853 brcmf_err("WLC_GET_WSEC error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001854 /* Ignore this error, may happen during DISASSOC */
1855 err = -EAGAIN;
1856 goto done;
1857 }
Hante Meulemanf09d0c02012-09-27 14:17:48 +02001858 switch (wsec & ~SES_OW_ENABLED) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001859 case WEP_ENABLED:
Arend van Spriel06bb1232012-09-27 14:17:56 +02001860 sec = &profile->sec;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001861 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1862 params.cipher = WLAN_CIPHER_SUITE_WEP40;
Arend van Spriel16886732012-12-05 15:26:04 +01001863 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001864 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1865 params.cipher = WLAN_CIPHER_SUITE_WEP104;
Arend van Spriel16886732012-12-05 15:26:04 +01001866 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001867 }
1868 break;
1869 case TKIP_ENABLED:
1870 params.cipher = WLAN_CIPHER_SUITE_TKIP;
Arend van Spriel16886732012-12-05 15:26:04 +01001871 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001872 break;
1873 case AES_ENABLED:
1874 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
Arend van Spriel16886732012-12-05 15:26:04 +01001875 brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001876 break;
1877 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01001878 brcmf_err("Invalid algo (0x%x)\n", wsec);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001879 err = -EINVAL;
1880 goto done;
1881 }
1882 callback(cookie, &params);
1883
1884done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001885 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001886 return err;
1887}
1888
1889static s32
1890brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
1891 struct net_device *ndev, u8 key_idx)
1892{
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001893 brcmf_dbg(INFO, "Not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001894
1895 return -EOPNOTSUPP;
1896}
1897
1898static s32
1899brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
Hante Meuleman1a873342012-09-27 14:17:54 +02001900 u8 *mac, struct station_info *sinfo)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001901{
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001902 struct brcmf_if *ifp = netdev_priv(ndev);
1903 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001904 struct brcmf_scb_val_le scb_val;
1905 int rssi;
1906 s32 rate;
1907 s32 err = 0;
Arend van Spriel06bb1232012-09-27 14:17:56 +02001908 u8 *bssid = profile->bssid;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001909 struct brcmf_sta_info_le sta_info_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001910
Arend van Sprield96b8012012-12-05 15:26:02 +01001911 brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
Arend van Sprielce81e312012-10-22 13:55:37 -07001912 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001913 return -EIO;
1914
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001915 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001916 memcpy(&sta_info_le, mac, ETH_ALEN);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001917 err = brcmf_fil_iovar_data_get(ifp, "sta_info",
Arend van Sprielac24be62012-10-22 10:36:23 -07001918 &sta_info_le,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001919 sizeof(sta_info_le));
Hante Meuleman1a873342012-09-27 14:17:54 +02001920 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001921 brcmf_err("GET STA INFO failed, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001922 goto done;
Hante Meuleman7f6c5622012-08-30 10:05:37 +02001923 }
Hante Meuleman1a873342012-09-27 14:17:54 +02001924 sinfo->filled = STATION_INFO_INACTIVE_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001925 sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
1926 if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001927 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07001928 sinfo->connected_time = le32_to_cpu(sta_info_le.in);
Hante Meuleman1a873342012-09-27 14:17:54 +02001929 }
Arend van Sprield96b8012012-12-05 15:26:02 +01001930 brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
1931 sinfo->inactive_time, sinfo->connected_time);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01001932 } else if (ifp->vif->mode == WL_MODE_BSS) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001933 if (memcmp(mac, bssid, ETH_ALEN)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001934 brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
1935 mac, bssid);
Hante Meuleman1a873342012-09-27 14:17:54 +02001936 err = -ENOENT;
1937 goto done;
1938 }
1939 /* Report the current tx rate */
Arend van Spriel0abb5f212012-10-22 13:55:32 -07001940 err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
Hante Meuleman1a873342012-09-27 14:17:54 +02001941 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001942 brcmf_err("Could not get rate (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001943 goto done;
1944 } else {
1945 sinfo->filled |= STATION_INFO_TX_BITRATE;
1946 sinfo->txrate.legacy = rate * 5;
Arend van Spriel16886732012-12-05 15:26:04 +01001947 brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
Hante Meuleman1a873342012-09-27 14:17:54 +02001948 }
1949
Arend van Sprielc1179032012-10-22 13:55:33 -07001950 if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
1951 &ifp->vif->sme_state)) {
Hante Meuleman1a873342012-09-27 14:17:54 +02001952 memset(&scb_val, 0, sizeof(scb_val));
Arend van Sprielc1179032012-10-22 13:55:33 -07001953 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
1954 &scb_val, sizeof(scb_val));
Hante Meuleman1a873342012-09-27 14:17:54 +02001955 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01001956 brcmf_err("Could not get rssi (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02001957 goto done;
1958 } else {
1959 rssi = le32_to_cpu(scb_val.val);
1960 sinfo->filled |= STATION_INFO_SIGNAL;
1961 sinfo->signal = rssi;
Arend van Spriel16886732012-12-05 15:26:04 +01001962 brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
Hante Meuleman1a873342012-09-27 14:17:54 +02001963 }
1964 }
1965 } else
1966 err = -EPERM;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001967done:
Arend van Sprield96b8012012-12-05 15:26:02 +01001968 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001969 return err;
1970}
1971
1972static s32
1973brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
1974 bool enabled, s32 timeout)
1975{
1976 s32 pm;
1977 s32 err = 0;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001978 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Sprielc1179032012-10-22 13:55:33 -07001979 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001980
Arend van Sprield96b8012012-12-05 15:26:02 +01001981 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001982
1983 /*
1984 * Powersave enable/disable request is coming from the
1985 * cfg80211 even before the interface is up. In that
1986 * scenario, driver will be storing the power save
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001987 * preference in cfg struct to apply this to
Arend van Spriel5b435de2011-10-05 13:19:03 +02001988 * FW later while initializing the dongle
1989 */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02001990 cfg->pwr_save = enabled;
Arend van Sprielce81e312012-10-22 13:55:37 -07001991 if (!check_vif_up(ifp->vif)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001992
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001993 brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001994 goto done;
1995 }
1996
1997 pm = enabled ? PM_FAST : PM_OFF;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01001998 brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999
Arend van Sprielc1179032012-10-22 13:55:33 -07002000 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002001 if (err) {
2002 if (err == -ENODEV)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002003 brcmf_err("net_device is not ready yet\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002004 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002005 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002006 }
2007done:
Arend van Sprield96b8012012-12-05 15:26:02 +01002008 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002009 return err;
2010}
2011
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002012static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
Roland Vossend34bf642011-10-18 14:03:01 +02002013 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002014{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002015 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002016 struct ieee80211_channel *notify_channel;
2017 struct cfg80211_bss *bss;
2018 struct ieee80211_supported_band *band;
2019 s32 err = 0;
2020 u16 channel;
2021 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002022 u16 notify_capability;
2023 u16 notify_interval;
2024 u8 *notify_ie;
2025 size_t notify_ielen;
2026 s32 notify_signal;
2027
2028 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002029 brcmf_err("Bss info is larger than buffer. Discarding\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002030 return 0;
2031 }
2032
2033 channel = bi->ctl_ch ? bi->ctl_ch :
2034 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2035
2036 if (channel <= CH_MAX_2G_CHANNEL)
2037 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2038 else
2039 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2040
2041 freq = ieee80211_channel_to_frequency(channel, band->band);
2042 notify_channel = ieee80211_get_channel(wiphy, freq);
2043
Arend van Spriel5b435de2011-10-05 13:19:03 +02002044 notify_capability = le16_to_cpu(bi->capability);
2045 notify_interval = le16_to_cpu(bi->beacon_period);
2046 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2047 notify_ielen = le32_to_cpu(bi->ie_length);
2048 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2049
Arend van Spriel16886732012-12-05 15:26:04 +01002050 brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
2051 brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
2052 brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
2053 brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
2054 brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002055
2056 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002057 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002058 notify_ielen, notify_signal, GFP_KERNEL);
2059
Franky Line78946e2011-11-10 20:30:34 +01002060 if (!bss)
2061 return -ENOMEM;
2062
2063 cfg80211_put_bss(bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064
2065 return err;
2066}
2067
Roland Vossen6f09be02011-10-18 14:03:02 +02002068static struct brcmf_bss_info_le *
2069next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2070{
2071 if (bss == NULL)
2072 return list->bss_info_le;
2073 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2074 le32_to_cpu(bss->length));
2075}
2076
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002077static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002078{
2079 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002080 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002081 s32 err = 0;
2082 int i;
2083
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002084 bss_list = cfg->bss_list;
Arend van Spriel0ecd8162012-11-05 16:22:11 -08002085 if (bss_list->count != 0 &&
2086 bss_list->version != BRCMF_BSS_INFO_VERSION) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002087 brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
2088 bss_list->version);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089 return -EOPNOTSUPP;
2090 }
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002091 brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
Hante Meulemanf07998952012-11-05 16:22:13 -08002092 for (i = 0; i < bss_list->count; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002093 bi = next_bss_le(bss_list, bi);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002094 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095 if (err)
2096 break;
2097 }
2098 return err;
2099}
2100
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002101static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002102 struct net_device *ndev, const u8 *bssid)
2103{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002104 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002105 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002106 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002107 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002108 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002109 u8 *buf = NULL;
2110 s32 err = 0;
2111 u16 channel;
2112 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002113 u16 notify_capability;
2114 u16 notify_interval;
2115 u8 *notify_ie;
2116 size_t notify_ielen;
2117 s32 notify_signal;
2118
Arend van Sprield96b8012012-12-05 15:26:02 +01002119 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002120
2121 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2122 if (buf == NULL) {
2123 err = -ENOMEM;
2124 goto CleanUp;
2125 }
2126
2127 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2128
Arend van Sprielac24be62012-10-22 10:36:23 -07002129 err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
2130 buf, WL_BSS_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002131 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002132 brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002133 goto CleanUp;
2134 }
2135
Roland Vossend34bf642011-10-18 14:03:01 +02002136 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002137
2138 channel = bi->ctl_ch ? bi->ctl_ch :
2139 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2140
2141 if (channel <= CH_MAX_2G_CHANNEL)
2142 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2143 else
2144 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2145
2146 freq = ieee80211_channel_to_frequency(channel, band->band);
2147 notify_channel = ieee80211_get_channel(wiphy, freq);
2148
Arend van Spriel5b435de2011-10-05 13:19:03 +02002149 notify_capability = le16_to_cpu(bi->capability);
2150 notify_interval = le16_to_cpu(bi->beacon_period);
2151 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2152 notify_ielen = le32_to_cpu(bi->ie_length);
2153 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2154
Arend van Spriel16886732012-12-05 15:26:04 +01002155 brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
2156 brcmf_dbg(CONN, "capability: %X\n", notify_capability);
2157 brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
2158 brcmf_dbg(CONN, "signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002159
Franky Line78946e2011-11-10 20:30:34 +01002160 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002161 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002162 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2163
Franky Line78946e2011-11-10 20:30:34 +01002164 if (!bss) {
2165 err = -ENOMEM;
2166 goto CleanUp;
2167 }
2168
2169 cfg80211_put_bss(bss);
2170
Arend van Spriel5b435de2011-10-05 13:19:03 +02002171CleanUp:
2172
2173 kfree(buf);
2174
Arend van Sprield96b8012012-12-05 15:26:02 +01002175 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002176
2177 return err;
2178}
2179
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002180static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181{
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002182 return vif->mode == WL_MODE_IBSS;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002183}
2184
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002185/*
2186 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2187 * triples, returning a pointer to the substring whose first element
2188 * matches tag
2189 */
2190static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
2191{
2192 struct brcmf_tlv *elt;
2193 int totlen;
2194
2195 elt = (struct brcmf_tlv *) buf;
2196 totlen = buflen;
2197
2198 /* find tagged parameter */
Hante Meuleman04012892012-09-27 14:17:49 +02002199 while (totlen >= TLV_HDR_LEN) {
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002200 int len = elt->len;
2201
2202 /* validate remaining totlen */
Hante Meuleman04012892012-09-27 14:17:49 +02002203 if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002204 return elt;
2205
Hante Meuleman04012892012-09-27 14:17:49 +02002206 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
2207 totlen -= (len + TLV_HDR_LEN);
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002208 }
2209
2210 return NULL;
2211}
2212
Hante Meuleman1a873342012-09-27 14:17:54 +02002213/* Is any of the tlvs the expected entry? If
2214 * not update the tlvs buffer pointer/length.
2215 */
2216static bool
2217brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
2218 u8 *oui, u32 oui_len, u8 type)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002219{
Hante Meuleman1a873342012-09-27 14:17:54 +02002220 /* If the contents match the OUI and the type */
2221 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
2222 !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
2223 type == ie[TLV_BODY_OFF + oui_len]) {
2224 return true;
2225 }
2226
2227 if (tlvs == NULL)
2228 return false;
2229 /* point to the next ie */
2230 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
2231 /* calculate the length of the rest of the buffer */
2232 *tlvs_len -= (int)(ie - *tlvs);
2233 /* update the pointer to the start of the buffer */
2234 *tlvs = ie;
2235
2236 return false;
2237}
2238
Franky Lin3cb91f52012-10-10 11:13:08 -07002239static struct brcmf_vs_tlv *
Hante Meuleman1a873342012-09-27 14:17:54 +02002240brcmf_find_wpaie(u8 *parse, u32 len)
2241{
2242 struct brcmf_tlv *ie;
2243
Arend van Spriel04b23122012-10-12 12:28:14 +02002244 while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
Hante Meuleman1a873342012-09-27 14:17:54 +02002245 if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
2246 WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
2247 return (struct brcmf_vs_tlv *)ie;
2248 }
2249 return NULL;
2250}
2251
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002252static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002253{
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07002254 struct net_device *ndev = cfg_to_ndev(cfg);
2255 struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
2256 struct brcmf_if *ifp = netdev_priv(ndev);
Roland Vossend34bf642011-10-18 14:03:01 +02002257 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002258 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002259 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002260 u16 beacon_interval;
2261 u8 dtim_period;
2262 size_t ie_len;
2263 u8 *ie;
2264 s32 err = 0;
2265
Arend van Sprield96b8012012-12-05 15:26:02 +01002266 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01002267 if (brcmf_is_ibssmode(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002268 return err;
2269
Arend van Spriel06bb1232012-09-27 14:17:56 +02002270 ssid = &profile->ssid;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002271
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002272 *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
Arend van Sprielac24be62012-10-22 10:36:23 -07002273 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07002274 cfg->extra_buf, WL_EXTRA_BUF_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002275 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002276 brcmf_err("Could not get bss info %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002277 goto update_bss_info_out;
2278 }
2279
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002280 bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
2281 err = brcmf_inform_single_bss(cfg, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002282 if (err)
2283 goto update_bss_info_out;
2284
2285 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2286 ie_len = le32_to_cpu(bi->ie_length);
2287 beacon_interval = le16_to_cpu(bi->beacon_period);
2288
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002289 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002290 if (tim)
2291 dtim_period = tim->data[1];
2292 else {
2293 /*
2294 * active scan was done so we could not get dtim
2295 * information out of probe response.
2296 * so we speficially query dtim information to dongle.
2297 */
2298 u32 var;
Arend van Sprielac24be62012-10-22 10:36:23 -07002299 err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002300 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002301 brcmf_err("wl dtim_assoc failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002302 goto update_bss_info_out;
2303 }
2304 dtim_period = (u8)var;
2305 }
2306
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307update_bss_info_out:
Arend van Sprield96b8012012-12-05 15:26:02 +01002308 brcmf_dbg(TRACE, "Exit");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002309 return err;
2310}
2311
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002312static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002313{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002314 struct escan_info *escan = &cfg->escan_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002315
Arend van Sprielc1179032012-10-22 13:55:33 -07002316 set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Hante Meulemanf07998952012-11-05 16:22:13 -08002317 if (cfg->scan_request) {
Arend van Spriel108a4be2012-09-19 22:21:07 +02002318 escan->escan_state = WL_ESCAN_STATE_IDLE;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002319 brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
Arend van Spriel108a4be2012-09-19 22:21:07 +02002320 }
Arend van Sprielc1179032012-10-22 13:55:33 -07002321 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2322 clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002323}
2324
Hante Meulemane756af52012-09-11 21:18:52 +02002325static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2326{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002327 struct brcmf_cfg80211_info *cfg =
2328 container_of(work, struct brcmf_cfg80211_info,
Hante Meulemane756af52012-09-11 21:18:52 +02002329 escan_timeout_work);
2330
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002331 brcmf_notify_escan_complete(cfg,
2332 cfg->escan_info.ndev, true, true);
Hante Meulemane756af52012-09-11 21:18:52 +02002333}
2334
2335static void brcmf_escan_timeout(unsigned long data)
2336{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002337 struct brcmf_cfg80211_info *cfg =
2338 (struct brcmf_cfg80211_info *)data;
Hante Meulemane756af52012-09-11 21:18:52 +02002339
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002340 if (cfg->scan_request) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002341 brcmf_err("timer expired\n");
Hante Meulemanf07998952012-11-05 16:22:13 -08002342 schedule_work(&cfg->escan_timeout_work);
Hante Meulemane756af52012-09-11 21:18:52 +02002343 }
2344}
2345
2346static s32
2347brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2348 struct brcmf_bss_info_le *bss_info_le)
2349{
2350 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2351 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2352 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2353 bss_info_le->SSID_len == bss->SSID_len &&
2354 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2355 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2356 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
Arend van Spriel029591f2012-09-19 22:21:06 +02002357 s16 bss_rssi = le16_to_cpu(bss->RSSI);
2358 s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
2359
Hante Meulemane756af52012-09-11 21:18:52 +02002360 /* preserve max RSSI if the measurements are
2361 * both on-channel or both off-channel
2362 */
Arend van Spriel029591f2012-09-19 22:21:06 +02002363 if (bss_info_rssi > bss_rssi)
Hante Meulemane756af52012-09-11 21:18:52 +02002364 bss->RSSI = bss_info_le->RSSI;
2365 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2366 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2367 /* preserve the on-channel rssi measurement
2368 * if the new measurement is off channel
2369 */
2370 bss->RSSI = bss_info_le->RSSI;
2371 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2372 }
2373 return 1;
2374 }
2375 return 0;
2376}
2377
2378static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002379brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
Hante Meulemane756af52012-09-11 21:18:52 +02002380 const struct brcmf_event_msg *e, void *data)
2381{
Arend van Spriel19937322012-11-05 16:22:32 -08002382 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2383 struct net_device *ndev = ifp->ndev;
Hante Meulemane756af52012-09-11 21:18:52 +02002384 s32 status;
2385 s32 err = 0;
2386 struct brcmf_escan_result_le *escan_result_le;
2387 struct brcmf_bss_info_le *bss_info_le;
2388 struct brcmf_bss_info_le *bss = NULL;
2389 u32 bi_length;
2390 struct brcmf_scan_results *list;
2391 u32 i;
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002392 bool aborted;
Hante Meulemane756af52012-09-11 21:18:52 +02002393
Arend van Spriel5c36b992012-11-14 18:46:05 -08002394 status = e->status;
Hante Meulemane756af52012-09-11 21:18:52 +02002395
Hante Meulemanf07998952012-11-05 16:22:13 -08002396 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002397 brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
2398 !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
Hante Meulemane756af52012-09-11 21:18:52 +02002399 return -EPERM;
2400 }
2401
2402 if (status == BRCMF_E_STATUS_PARTIAL) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002403 brcmf_dbg(SCAN, "ESCAN Partial result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002404 escan_result_le = (struct brcmf_escan_result_le *) data;
2405 if (!escan_result_le) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002406 brcmf_err("Invalid escan result (NULL pointer)\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002407 goto exit;
2408 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002409 if (!cfg->scan_request) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002410 brcmf_dbg(SCAN, "result without cfg80211 request\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002411 goto exit;
2412 }
2413
2414 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002415 brcmf_err("Invalid bss_count %d: ignoring\n",
2416 escan_result_le->bss_count);
Hante Meulemane756af52012-09-11 21:18:52 +02002417 goto exit;
2418 }
2419 bss_info_le = &escan_result_le->bss_info_le;
2420
2421 bi_length = le32_to_cpu(bss_info_le->length);
2422 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2423 WL_ESCAN_RESULTS_FIXED_SIZE)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002424 brcmf_err("Invalid bss_info length %d: ignoring\n",
2425 bi_length);
Hante Meulemane756af52012-09-11 21:18:52 +02002426 goto exit;
2427 }
2428
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002429 if (!(cfg_to_wiphy(cfg)->interface_modes &
Hante Meulemane756af52012-09-11 21:18:52 +02002430 BIT(NL80211_IFTYPE_ADHOC))) {
2431 if (le16_to_cpu(bss_info_le->capability) &
2432 WLAN_CAPABILITY_IBSS) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002433 brcmf_err("Ignoring IBSS result\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002434 goto exit;
2435 }
2436 }
2437
2438 list = (struct brcmf_scan_results *)
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002439 cfg->escan_info.escan_buf;
Hante Meulemane756af52012-09-11 21:18:52 +02002440 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002441 brcmf_err("Buffer is too small: ignoring\n");
Hante Meulemane756af52012-09-11 21:18:52 +02002442 goto exit;
2443 }
2444
2445 for (i = 0; i < list->count; i++) {
2446 bss = bss ? (struct brcmf_bss_info_le *)
2447 ((unsigned char *)bss +
2448 le32_to_cpu(bss->length)) : list->bss_info_le;
2449 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2450 goto exit;
2451 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002452 memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
Hante Meulemane756af52012-09-11 21:18:52 +02002453 bss_info_le, bi_length);
2454 list->version = le32_to_cpu(bss_info_le->version);
2455 list->buflen += bi_length;
2456 list->count++;
2457 } else {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002458 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2459 if (cfg->scan_request) {
2460 cfg->bss_list = (struct brcmf_scan_results *)
2461 cfg->escan_info.escan_buf;
2462 brcmf_inform_bss(cfg);
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002463 aborted = status != BRCMF_E_STATUS_SUCCESS;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002464 brcmf_notify_escan_complete(cfg, ndev, aborted,
Arend van Spriel97ed15c2012-09-13 21:12:06 +02002465 false);
Hante Meulemane756af52012-09-11 21:18:52 +02002466 } else
Arend van Spriel57d6e912012-12-05 15:26:00 +01002467 brcmf_err("Unexpected scan result 0x%x\n", status);
Hante Meulemane756af52012-09-11 21:18:52 +02002468 }
2469exit:
2470 return err;
2471}
2472
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002473static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
Hante Meulemane756af52012-09-11 21:18:52 +02002474{
Arend van Spriel5c36b992012-11-14 18:46:05 -08002475 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2476 brcmf_cfg80211_escan_handler);
Hante Meulemanf07998952012-11-05 16:22:13 -08002477 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2478 /* Init scan_timeout timer */
2479 init_timer(&cfg->escan_timeout);
2480 cfg->escan_timeout.data = (unsigned long) cfg;
2481 cfg->escan_timeout.function = brcmf_escan_timeout;
2482 INIT_WORK(&cfg->escan_timeout_work,
2483 brcmf_cfg80211_escan_timeout_worker);
Hante Meulemane756af52012-09-11 21:18:52 +02002484}
2485
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002486static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002487{
2488 if (ms < 1000 / HZ) {
2489 cond_resched();
2490 mdelay(ms);
2491 } else {
2492 msleep(ms);
2493 }
2494}
2495
2496static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2497{
Arend van Sprield96b8012012-12-05 15:26:02 +01002498 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002499
Arend van Spriel5b435de2011-10-05 13:19:03 +02002500 return 0;
2501}
2502
2503static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2504 struct cfg80211_wowlan *wow)
2505{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002506 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2507 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Spriel7d641072012-10-22 13:55:39 -07002508 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002509
Arend van Sprield96b8012012-12-05 15:26:02 +01002510 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002511
2512 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002513 * if the primary net_device is not READY there is nothing
2514 * we can do but pray resume goes smoothly.
Arend van Spriel5b435de2011-10-05 13:19:03 +02002515 */
Arend van Spriel7d641072012-10-22 13:55:39 -07002516 vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
2517 if (!check_vif_up(vif))
2518 goto exit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002519
Arend van Spriel7d641072012-10-22 13:55:39 -07002520 list_for_each_entry(vif, &cfg->vif_list, list) {
2521 if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
2522 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002523 /*
Arend van Spriel7d641072012-10-22 13:55:39 -07002524 * While going to suspend if associated with AP disassociate
2525 * from AP to save power while system is in suspended state
Arend van Spriel5b435de2011-10-05 13:19:03 +02002526 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002527 brcmf_link_down(vif);
Arend van Spriel7d641072012-10-22 13:55:39 -07002528
Arend van Spriel903e0ee2012-11-28 21:44:11 +01002529 /* Make sure WPA_Supplicant receives all the event
2530 * generated due to DISASSOC call to the fw to keep
2531 * the state fw and WPA_Supplicant state consistent
2532 */
2533 brcmf_delay(500);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002534 }
2535
Arend van Spriel7d641072012-10-22 13:55:39 -07002536 /* end any scanning */
2537 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002538 brcmf_abort_scanning(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002539
2540 /* Turn off watchdog timer */
Arend van Spriel7d641072012-10-22 13:55:39 -07002541 brcmf_set_mpc(ndev, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002542
Arend van Spriel7d641072012-10-22 13:55:39 -07002543exit:
Arend van Sprield96b8012012-12-05 15:26:02 +01002544 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel7d641072012-10-22 13:55:39 -07002545 /* clear any scanning activity */
2546 cfg->scan_status = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002547 return 0;
2548}
2549
2550static __used s32
Arend van Spriel5b435de2011-10-05 13:19:03 +02002551brcmf_update_pmklist(struct net_device *ndev,
2552 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2553{
2554 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002555 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002556
Arend van Spriel40c8e952011-10-12 20:51:20 +02002557 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2558
Arend van Spriel16886732012-12-05 15:26:04 +01002559 brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002560 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel16886732012-12-05 15:26:04 +01002561 brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
2562 &pmk_list->pmkids.pmkid[i].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002563 for (j = 0; j < WLAN_PMKID_LEN; j++)
Arend van Spriel16886732012-12-05 15:26:04 +01002564 brcmf_dbg(CONN, "%02x\n",
2565 pmk_list->pmkids.pmkid[i].PMKID[j]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002566 }
2567
2568 if (!err)
Arend van Sprielac24be62012-10-22 10:36:23 -07002569 brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
2570 (char *)pmk_list, sizeof(*pmk_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002571
2572 return err;
2573}
2574
2575static s32
2576brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2577 struct cfg80211_pmksa *pmksa)
2578{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002579 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002580 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002581 struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002582 s32 err = 0;
2583 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002584 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002585
Arend van Sprield96b8012012-12-05 15:26:02 +01002586 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002587 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002588 return -EIO;
2589
Arend van Spriel40c8e952011-10-12 20:51:20 +02002590 pmkid_len = le32_to_cpu(pmkids->npmkid);
2591 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002592 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2593 break;
2594 if (i < WL_NUM_PMKIDS_MAX) {
2595 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2596 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002597 if (i == pmkid_len) {
2598 pmkid_len++;
2599 pmkids->npmkid = cpu_to_le32(pmkid_len);
2600 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002601 } else
2602 err = -EINVAL;
2603
Arend van Spriel16886732012-12-05 15:26:04 +01002604 brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
2605 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002606 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002607 brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002608
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002609 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002610
Arend van Sprield96b8012012-12-05 15:26:02 +01002611 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002612 return err;
2613}
2614
2615static s32
2616brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2617 struct cfg80211_pmksa *pmksa)
2618{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002619 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002620 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002621 struct pmkid_list pmkid;
2622 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002623 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002624
Arend van Sprield96b8012012-12-05 15:26:02 +01002625 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002626 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002627 return -EIO;
2628
2629 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2630 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2631
Arend van Spriel16886732012-12-05 15:26:04 +01002632 brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2633 &pmkid.pmkid[0].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002634 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel16886732012-12-05 15:26:04 +01002635 brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002636
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002637 pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002638 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002639 if (!memcmp
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002640 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002641 ETH_ALEN))
2642 break;
2643
Arend van Spriel40c8e952011-10-12 20:51:20 +02002644 if ((pmkid_len > 0)
2645 && (i < pmkid_len)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002646 memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002647 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002648 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002649 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
2650 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002651 ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002652 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
2653 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002654 WLAN_PMKID_LEN);
2655 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002656 cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002657 } else
2658 err = -EINVAL;
2659
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002660 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002661
Arend van Sprield96b8012012-12-05 15:26:02 +01002662 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002663 return err;
2664
2665}
2666
2667static s32
2668brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2669{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002670 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07002671 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002672 s32 err = 0;
2673
Arend van Sprield96b8012012-12-05 15:26:02 +01002674 brcmf_dbg(TRACE, "Enter\n");
Arend van Sprielce81e312012-10-22 13:55:37 -07002675 if (!check_vif_up(ifp->vif))
Arend van Spriel5b435de2011-10-05 13:19:03 +02002676 return -EIO;
2677
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002678 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
2679 err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002680
Arend van Sprield96b8012012-12-05 15:26:02 +01002681 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002682 return err;
2683
2684}
2685
Arend van Spriele5806072012-09-19 22:21:08 +02002686/*
2687 * PFN result doesn't have all the info which are
2688 * required by the supplicant
2689 * (For e.g IEs) Do a target Escan so that sched scan results are reported
2690 * via wl_inform_single_bss in the required format. Escan does require the
2691 * scan request in the form of cfg80211_scan_request. For timebeing, create
2692 * cfg80211_scan_request one out of the received PNO event.
2693 */
2694static s32
Arend van Spriel19937322012-11-05 16:22:32 -08002695brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
Arend van Spriele5806072012-09-19 22:21:08 +02002696 const struct brcmf_event_msg *e, void *data)
2697{
Arend van Spriel19937322012-11-05 16:22:32 -08002698 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2699 struct net_device *ndev = ifp->ndev;
Arend van Spriele5806072012-09-19 22:21:08 +02002700 struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
2701 struct cfg80211_scan_request *request = NULL;
2702 struct cfg80211_ssid *ssid = NULL;
2703 struct ieee80211_channel *channel = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002704 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002705 int err = 0;
2706 int channel_req = 0;
2707 int band = 0;
2708 struct brcmf_pno_scanresults_le *pfn_result;
2709 u32 result_count;
2710 u32 status;
2711
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002712 brcmf_dbg(SCAN, "Enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002713
Arend van Spriel5c36b992012-11-14 18:46:05 -08002714 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002715 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002716 return 0;
2717 }
2718
2719 pfn_result = (struct brcmf_pno_scanresults_le *)data;
2720 result_count = le32_to_cpu(pfn_result->count);
2721 status = le32_to_cpu(pfn_result->status);
2722
2723 /*
2724 * PFN event is limited to fit 512 bytes so we may get
2725 * multiple NET_FOUND events. For now place a warning here.
2726 */
2727 WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002728 brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
Arend van Spriele5806072012-09-19 22:21:08 +02002729 if (result_count > 0) {
2730 int i;
2731
2732 request = kzalloc(sizeof(*request), GFP_KERNEL);
Dan Carpenter58901d12012-09-26 10:21:48 +03002733 ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
2734 channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
Arend van Spriele5806072012-09-19 22:21:08 +02002735 if (!request || !ssid || !channel) {
2736 err = -ENOMEM;
2737 goto out_err;
2738 }
2739
2740 request->wiphy = wiphy;
2741 data += sizeof(struct brcmf_pno_scanresults_le);
2742 netinfo_start = (struct brcmf_pno_net_info_le *)data;
2743
2744 for (i = 0; i < result_count; i++) {
2745 netinfo = &netinfo_start[i];
2746 if (!netinfo) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002747 brcmf_err("Invalid netinfo ptr. index: %d\n",
2748 i);
Arend van Spriele5806072012-09-19 22:21:08 +02002749 err = -EINVAL;
2750 goto out_err;
2751 }
2752
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002753 brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
2754 netinfo->SSID, netinfo->channel);
Arend van Spriele5806072012-09-19 22:21:08 +02002755 memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
2756 ssid[i].ssid_len = netinfo->SSID_len;
2757 request->n_ssids++;
2758
2759 channel_req = netinfo->channel;
2760 if (channel_req <= CH_MAX_2G_CHANNEL)
2761 band = NL80211_BAND_2GHZ;
2762 else
2763 band = NL80211_BAND_5GHZ;
2764 channel[i].center_freq =
2765 ieee80211_channel_to_frequency(channel_req,
2766 band);
2767 channel[i].band = band;
2768 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
2769 request->channels[i] = &channel[i];
2770 request->n_channels++;
2771 }
2772
2773 /* assign parsed ssid array */
2774 if (request->n_ssids)
2775 request->ssids = &ssid[0];
2776
Arend van Sprielc1179032012-10-22 13:55:33 -07002777 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriele5806072012-09-19 22:21:08 +02002778 /* Abort any on-going scan */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002779 brcmf_abort_scanning(cfg);
Arend van Spriele5806072012-09-19 22:21:08 +02002780 }
2781
Arend van Sprielc1179032012-10-22 13:55:33 -07002782 set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002783 err = brcmf_do_escan(cfg, wiphy, ndev, request);
Arend van Spriele5806072012-09-19 22:21:08 +02002784 if (err) {
Arend van Sprielc1179032012-10-22 13:55:33 -07002785 clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002786 goto out_err;
2787 }
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002788 cfg->sched_escan = true;
2789 cfg->scan_request = request;
Arend van Spriele5806072012-09-19 22:21:08 +02002790 } else {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002791 brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002792 goto out_err;
2793 }
2794
2795 kfree(ssid);
2796 kfree(channel);
2797 kfree(request);
2798 return 0;
2799
2800out_err:
2801 kfree(ssid);
2802 kfree(channel);
2803 kfree(request);
2804 cfg80211_sched_scan_stopped(wiphy);
2805 return err;
2806}
2807
Arend van Spriele5806072012-09-19 22:21:08 +02002808static int brcmf_dev_pno_clean(struct net_device *ndev)
2809{
Arend van Spriele5806072012-09-19 22:21:08 +02002810 int ret;
2811
2812 /* Disable pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002813 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002814 if (ret == 0) {
2815 /* clear pfn */
Arend van Sprielac24be62012-10-22 10:36:23 -07002816 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
2817 NULL, 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002818 }
2819 if (ret < 0)
Arend van Spriel57d6e912012-12-05 15:26:00 +01002820 brcmf_err("failed code %d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002821
2822 return ret;
2823}
2824
2825static int brcmf_dev_pno_config(struct net_device *ndev)
2826{
2827 struct brcmf_pno_param_le pfn_param;
Arend van Spriele5806072012-09-19 22:21:08 +02002828
2829 memset(&pfn_param, 0, sizeof(pfn_param));
2830 pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
2831
2832 /* set extra pno params */
2833 pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
2834 pfn_param.repeat = BRCMF_PNO_REPEAT;
2835 pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
2836
2837 /* set up pno scan fr */
2838 pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
2839
Arend van Sprielac24be62012-10-22 10:36:23 -07002840 return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
2841 &pfn_param, sizeof(pfn_param));
Arend van Spriele5806072012-09-19 22:21:08 +02002842}
2843
2844static int
2845brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
2846 struct net_device *ndev,
2847 struct cfg80211_sched_scan_request *request)
2848{
Arend van Sprielc1179032012-10-22 13:55:33 -07002849 struct brcmf_if *ifp = netdev_priv(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002850 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002851 struct brcmf_pno_net_param_le pfn;
2852 int i;
2853 int ret = 0;
2854
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002855 brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
2856 request->n_match_sets, request->n_ssids);
Arend van Sprielc1179032012-10-22 13:55:33 -07002857 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002858 brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
Arend van Spriele5806072012-09-19 22:21:08 +02002859 return -EAGAIN;
2860 }
2861
2862 if (!request || !request->n_ssids || !request->n_match_sets) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002863 brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
2864 request ? request->n_ssids : 0);
Arend van Spriele5806072012-09-19 22:21:08 +02002865 return -EINVAL;
2866 }
2867
2868 if (request->n_ssids > 0) {
2869 for (i = 0; i < request->n_ssids; i++) {
2870 /* Active scan req for ssids */
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002871 brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
2872 request->ssids[i].ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002873
2874 /*
2875 * match_set ssids is a supert set of n_ssid list,
2876 * so we need not add these set seperately.
2877 */
2878 }
2879 }
2880
2881 if (request->n_match_sets > 0) {
2882 /* clean up everything */
2883 ret = brcmf_dev_pno_clean(ndev);
2884 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002885 brcmf_err("failed error=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002886 return ret;
2887 }
2888
2889 /* configure pno */
2890 ret = brcmf_dev_pno_config(ndev);
2891 if (ret < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002892 brcmf_err("PNO setup failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002893 return -EINVAL;
2894 }
2895
2896 /* configure each match set */
2897 for (i = 0; i < request->n_match_sets; i++) {
2898 struct cfg80211_ssid *ssid;
2899 u32 ssid_len;
2900
2901 ssid = &request->match_sets[i].ssid;
2902 ssid_len = ssid->ssid_len;
2903
2904 if (!ssid_len) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002905 brcmf_err("skip broadcast ssid\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002906 continue;
2907 }
2908 pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
2909 pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
2910 pfn.wsec = cpu_to_le32(0);
2911 pfn.infra = cpu_to_le32(1);
2912 pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
2913 pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
2914 memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
Arend van Sprielc1179032012-10-22 13:55:33 -07002915 ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
Arend van Sprielac24be62012-10-22 10:36:23 -07002916 sizeof(pfn));
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002917 brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
2918 ret == 0 ? "set" : "failed", ssid->ssid);
Arend van Spriele5806072012-09-19 22:21:08 +02002919 }
2920 /* Enable the PNO */
Arend van Sprielc1179032012-10-22 13:55:33 -07002921 if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002922 brcmf_err("PNO enable failed!! ret=%d\n", ret);
Arend van Spriele5806072012-09-19 22:21:08 +02002923 return -EINVAL;
2924 }
2925 } else {
2926 return -EINVAL;
2927 }
2928
2929 return 0;
2930}
2931
2932static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2933 struct net_device *ndev)
2934{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002935 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriele5806072012-09-19 22:21:08 +02002936
Arend van Spriel4e8a0082012-12-05 15:26:03 +01002937 brcmf_dbg(SCAN, "enter\n");
Arend van Spriele5806072012-09-19 22:21:08 +02002938 brcmf_dev_pno_clean(ndev);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002939 if (cfg->sched_escan)
2940 brcmf_notify_escan_complete(cfg, ndev, true, true);
Arend van Spriele5806072012-09-19 22:21:08 +02002941 return 0;
2942}
Arend van Spriele5806072012-09-19 22:21:08 +02002943
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002944#ifdef CONFIG_NL80211_TESTMODE
2945static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
2946{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02002947 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
Arend van Spriel3eacf862012-10-22 13:55:30 -07002948 struct net_device *ndev = cfg_to_ndev(cfg);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002949 struct brcmf_dcmd *dcmd = data;
2950 struct sk_buff *reply;
2951 int ret;
2952
Arend van Sprield96b8012012-12-05 15:26:02 +01002953 brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
2954 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07002955
2956 if (dcmd->set)
Arend van Sprielac24be62012-10-22 10:36:23 -07002957 ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
2958 dcmd->buf, dcmd->len);
Hante Meulemanf368a5b2012-10-22 10:36:16 -07002959 else
Arend van Sprielac24be62012-10-22 10:36:23 -07002960 ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
2961 dcmd->buf, dcmd->len);
Arend van Sprielcbaa1772012-08-30 19:43:02 +02002962 if (ret == 0) {
2963 reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
2964 nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
2965 ret = cfg80211_testmode_reply(reply);
2966 }
2967 return ret;
2968}
2969#endif
2970
Hante Meuleman1f170112013-02-06 18:40:38 +01002971static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
Hante Meuleman1a873342012-09-27 14:17:54 +02002972{
2973 s32 err;
2974
2975 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07002976 err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02002977 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002978 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002979 return err;
2980 }
2981 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07002982 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02002983 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002984 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002985 return err;
2986 }
2987 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07002988 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
Hante Meuleman1a873342012-09-27 14:17:54 +02002989 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01002990 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02002991 return err;
2992 }
2993
2994 return 0;
2995}
2996
2997static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
2998{
2999 if (is_rsn_ie)
3000 return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
3001
3002 return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
3003}
3004
3005static s32
3006brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
Arend van Spriel34778522012-11-05 16:22:19 -08003007 bool is_rsn_ie)
Hante Meuleman1a873342012-09-27 14:17:54 +02003008{
Arend van Sprielac24be62012-10-22 10:36:23 -07003009 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003010 u32 auth = 0; /* d11 open authentication */
3011 u16 count;
3012 s32 err = 0;
3013 s32 len = 0;
3014 u32 i;
3015 u32 wsec;
3016 u32 pval = 0;
3017 u32 gval = 0;
3018 u32 wpa_auth = 0;
3019 u32 offset;
3020 u8 *data;
3021 u16 rsn_cap;
3022 u32 wme_bss_disable;
3023
Arend van Sprield96b8012012-12-05 15:26:02 +01003024 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003025 if (wpa_ie == NULL)
3026 goto exit;
3027
3028 len = wpa_ie->len + TLV_HDR_LEN;
3029 data = (u8 *)wpa_ie;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003030 offset = TLV_HDR_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003031 if (!is_rsn_ie)
3032 offset += VS_IE_FIXED_HDR_LEN;
Hante Meuleman619c5a92013-01-02 15:12:39 +01003033 else
3034 offset += WPA_IE_VERSION_LEN;
Hante Meuleman1a873342012-09-27 14:17:54 +02003035
3036 /* check for multicast cipher suite */
3037 if (offset + WPA_IE_MIN_OUI_LEN > len) {
3038 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003039 brcmf_err("no multicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003040 goto exit;
3041 }
3042
3043 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3044 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003045 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003046 goto exit;
3047 }
3048 offset += TLV_OUI_LEN;
3049
3050 /* pick up multicast cipher */
3051 switch (data[offset]) {
3052 case WPA_CIPHER_NONE:
3053 gval = 0;
3054 break;
3055 case WPA_CIPHER_WEP_40:
3056 case WPA_CIPHER_WEP_104:
3057 gval = WEP_ENABLED;
3058 break;
3059 case WPA_CIPHER_TKIP:
3060 gval = TKIP_ENABLED;
3061 break;
3062 case WPA_CIPHER_AES_CCM:
3063 gval = AES_ENABLED;
3064 break;
3065 default:
3066 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003067 brcmf_err("Invalid multi cast cipher info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003068 goto exit;
3069 }
3070
3071 offset++;
3072 /* walk thru unicast cipher list and pick up what we recognize */
3073 count = data[offset] + (data[offset + 1] << 8);
3074 offset += WPA_IE_SUITE_COUNT_LEN;
3075 /* Check for unicast suite(s) */
3076 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3077 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003078 brcmf_err("no unicast cipher suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003079 goto exit;
3080 }
3081 for (i = 0; i < count; i++) {
3082 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3083 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003084 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003085 goto exit;
3086 }
3087 offset += TLV_OUI_LEN;
3088 switch (data[offset]) {
3089 case WPA_CIPHER_NONE:
3090 break;
3091 case WPA_CIPHER_WEP_40:
3092 case WPA_CIPHER_WEP_104:
3093 pval |= WEP_ENABLED;
3094 break;
3095 case WPA_CIPHER_TKIP:
3096 pval |= TKIP_ENABLED;
3097 break;
3098 case WPA_CIPHER_AES_CCM:
3099 pval |= AES_ENABLED;
3100 break;
3101 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003102 brcmf_err("Ivalid unicast security info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003103 }
3104 offset++;
3105 }
3106 /* walk thru auth management suite list and pick up what we recognize */
3107 count = data[offset] + (data[offset + 1] << 8);
3108 offset += WPA_IE_SUITE_COUNT_LEN;
3109 /* Check for auth key management suite(s) */
3110 if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
3111 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003112 brcmf_err("no auth key mgmt suite\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003113 goto exit;
3114 }
3115 for (i = 0; i < count; i++) {
3116 if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
3117 err = -EINVAL;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003118 brcmf_err("ivalid OUI\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003119 goto exit;
3120 }
3121 offset += TLV_OUI_LEN;
3122 switch (data[offset]) {
3123 case RSN_AKM_NONE:
Arend van Sprield96b8012012-12-05 15:26:02 +01003124 brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003125 wpa_auth |= WPA_AUTH_NONE;
3126 break;
3127 case RSN_AKM_UNSPECIFIED:
Arend van Sprield96b8012012-12-05 15:26:02 +01003128 brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003129 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
3130 (wpa_auth |= WPA_AUTH_UNSPECIFIED);
3131 break;
3132 case RSN_AKM_PSK:
Arend van Sprield96b8012012-12-05 15:26:02 +01003133 brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003134 is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
3135 (wpa_auth |= WPA_AUTH_PSK);
3136 break;
3137 default:
Arend van Spriel57d6e912012-12-05 15:26:00 +01003138 brcmf_err("Ivalid key mgmt info\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003139 }
3140 offset++;
3141 }
3142
3143 if (is_rsn_ie) {
3144 wme_bss_disable = 1;
3145 if ((offset + RSN_CAP_LEN) <= len) {
3146 rsn_cap = data[offset] + (data[offset + 1] << 8);
3147 if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
3148 wme_bss_disable = 0;
3149 }
3150 /* set wme_bss_disable to sync RSN Capabilities */
Arend van Sprielac24be62012-10-22 10:36:23 -07003151 err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003152 wme_bss_disable);
Hante Meuleman1a873342012-09-27 14:17:54 +02003153 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003154 brcmf_err("wme_bss_disable error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003155 goto exit;
3156 }
3157 }
3158 /* FOR WPS , set SES_OW_ENABLED */
3159 wsec = (pval | gval | SES_OW_ENABLED);
3160
3161 /* set auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003162 err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003163 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003164 brcmf_err("auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003165 goto exit;
3166 }
3167 /* set wsec */
Arend van Sprielac24be62012-10-22 10:36:23 -07003168 err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
Hante Meuleman1a873342012-09-27 14:17:54 +02003169 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003170 brcmf_err("wsec error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003171 goto exit;
3172 }
3173 /* set upper-layer auth */
Arend van Sprielac24be62012-10-22 10:36:23 -07003174 err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
Hante Meuleman1a873342012-09-27 14:17:54 +02003175 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003176 brcmf_err("wpa_auth error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003177 goto exit;
3178 }
3179
3180exit:
3181 return err;
3182}
3183
3184static s32
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003185brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
Hante Meuleman1a873342012-09-27 14:17:54 +02003186 struct parsed_vndr_ies *vndr_ies)
3187{
3188 s32 err = 0;
3189 struct brcmf_vs_tlv *vndrie;
3190 struct brcmf_tlv *ie;
3191 struct parsed_vndr_ie_info *parsed_info;
3192 s32 remaining_len;
3193
3194 remaining_len = (s32)vndr_ie_len;
3195 memset(vndr_ies, 0, sizeof(*vndr_ies));
3196
3197 ie = (struct brcmf_tlv *)vndr_ie_buf;
3198 while (ie) {
3199 if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
3200 goto next;
3201 vndrie = (struct brcmf_vs_tlv *)ie;
3202 /* len should be bigger than OUI length + one */
3203 if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003204 brcmf_err("invalid vndr ie. length is too small %d\n",
3205 vndrie->len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003206 goto next;
3207 }
3208 /* if wpa or wme ie, do not add ie */
3209 if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
3210 ((vndrie->oui_type == WPA_OUI_TYPE) ||
3211 (vndrie->oui_type == WME_OUI_TYPE))) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003212 brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003213 goto next;
3214 }
3215
3216 parsed_info = &vndr_ies->ie_info[vndr_ies->count];
3217
3218 /* save vndr ie information */
3219 parsed_info->ie_ptr = (char *)vndrie;
3220 parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
3221 memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
3222
3223 vndr_ies->count++;
3224
Arend van Sprield96b8012012-12-05 15:26:02 +01003225 brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
3226 parsed_info->vndrie.oui[0],
3227 parsed_info->vndrie.oui[1],
3228 parsed_info->vndrie.oui[2],
3229 parsed_info->vndrie.oui_type);
Hante Meuleman1a873342012-09-27 14:17:54 +02003230
3231 if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
3232 break;
3233next:
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003234 remaining_len -= (ie->len + TLV_HDR_LEN);
3235 if (remaining_len <= TLV_HDR_LEN)
Hante Meuleman1a873342012-09-27 14:17:54 +02003236 ie = NULL;
3237 else
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003238 ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
3239 TLV_HDR_LEN);
Hante Meuleman1a873342012-09-27 14:17:54 +02003240 }
3241 return err;
3242}
3243
3244static u32
3245brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
3246{
3247
3248 __le32 iecount_le;
3249 __le32 pktflag_le;
3250
3251 strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
3252 iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
3253
3254 iecount_le = cpu_to_le32(1);
3255 memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
3256
3257 pktflag_le = cpu_to_le32(pktflag);
3258 memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
3259
3260 memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
3261
3262 return ie_len + VNDR_IE_HDR_SIZE;
3263}
3264
Arend van Spriel3082b9b2012-11-05 16:22:12 -08003265static
Arend van Spriel1332e262012-11-05 16:22:18 -08003266s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
3267 const u8 *vndr_ie_buf, u32 vndr_ie_len)
Hante Meuleman1a873342012-09-27 14:17:54 +02003268{
Arend van Spriel1332e262012-11-05 16:22:18 -08003269 struct brcmf_if *ifp;
3270 struct vif_saved_ie *saved_ie;
Hante Meuleman1a873342012-09-27 14:17:54 +02003271 s32 err = 0;
3272 u8 *iovar_ie_buf;
3273 u8 *curr_ie_buf;
3274 u8 *mgmt_ie_buf = NULL;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003275 int mgmt_ie_buf_len;
Dan Carpenter81118d12012-10-10 11:13:07 -07003276 u32 *mgmt_ie_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003277 u32 del_add_ie_buf_len = 0;
3278 u32 total_ie_buf_len = 0;
3279 u32 parsed_ie_buf_len = 0;
3280 struct parsed_vndr_ies old_vndr_ies;
3281 struct parsed_vndr_ies new_vndr_ies;
3282 struct parsed_vndr_ie_info *vndrie_info;
3283 s32 i;
3284 u8 *ptr;
Dan Carpenter3e4f3192012-10-10 11:13:12 -07003285 int remained_buf_len;
Hante Meuleman1a873342012-09-27 14:17:54 +02003286
Arend van Spriel1332e262012-11-05 16:22:18 -08003287 if (!vif)
3288 return -ENODEV;
3289 ifp = vif->ifp;
3290 saved_ie = &vif->saved_ie;
3291
Arend van Sprield96b8012012-12-05 15:26:02 +01003292 brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
Hante Meuleman1a873342012-09-27 14:17:54 +02003293 iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3294 if (!iovar_ie_buf)
3295 return -ENOMEM;
3296 curr_ie_buf = iovar_ie_buf;
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003297 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003298 switch (pktflag) {
3299 case VNDR_IE_PRBRSP_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003300 mgmt_ie_buf = saved_ie->probe_res_ie;
3301 mgmt_ie_len = &saved_ie->probe_res_ie_len;
3302 mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003303 break;
3304 case VNDR_IE_BEACON_FLAG:
Arend van Spriel8ff5dc92012-10-22 13:55:41 -07003305 mgmt_ie_buf = saved_ie->beacon_ie;
3306 mgmt_ie_len = &saved_ie->beacon_ie_len;
3307 mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
Hante Meuleman1a873342012-09-27 14:17:54 +02003308 break;
3309 default:
3310 err = -EPERM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003311 brcmf_err("not suitable type\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003312 goto exit;
3313 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003314 } else {
3315 err = -EPERM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003316 brcmf_err("not suitable type\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003317 goto exit;
3318 }
3319
3320 if (vndr_ie_len > mgmt_ie_buf_len) {
3321 err = -ENOMEM;
Arend van Spriel57d6e912012-12-05 15:26:00 +01003322 brcmf_err("extra IE size too big\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003323 goto exit;
3324 }
3325
3326 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
3327 if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
3328 ptr = curr_ie_buf;
3329 brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
3330 for (i = 0; i < new_vndr_ies.count; i++) {
3331 vndrie_info = &new_vndr_ies.ie_info[i];
3332 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
3333 vndrie_info->ie_len);
3334 parsed_ie_buf_len += vndrie_info->ie_len;
3335 }
3336 }
3337
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003338 if (mgmt_ie_buf && *mgmt_ie_len) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003339 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
3340 (memcmp(mgmt_ie_buf, curr_ie_buf,
3341 parsed_ie_buf_len) == 0)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003342 brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003343 goto exit;
3344 }
3345
3346 /* parse old vndr_ie */
3347 brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
3348
3349 /* make a command to delete old ie */
3350 for (i = 0; i < old_vndr_ies.count; i++) {
3351 vndrie_info = &old_vndr_ies.ie_info[i];
3352
Arend van Sprield96b8012012-12-05 15:26:02 +01003353 brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
3354 vndrie_info->vndrie.id,
3355 vndrie_info->vndrie.len,
3356 vndrie_info->vndrie.oui[0],
3357 vndrie_info->vndrie.oui[1],
3358 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003359
3360 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3361 vndrie_info->ie_ptr,
3362 vndrie_info->ie_len,
3363 "del");
3364 curr_ie_buf += del_add_ie_buf_len;
3365 total_ie_buf_len += del_add_ie_buf_len;
3366 }
3367 }
3368
3369 *mgmt_ie_len = 0;
3370 /* Add if there is any extra IE */
3371 if (mgmt_ie_buf && parsed_ie_buf_len) {
3372 ptr = mgmt_ie_buf;
3373
3374 remained_buf_len = mgmt_ie_buf_len;
3375
3376 /* make a command to add new ie */
3377 for (i = 0; i < new_vndr_ies.count; i++) {
3378 vndrie_info = &new_vndr_ies.ie_info[i];
3379
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003380 /* verify remained buf size before copy data */
3381 if (remained_buf_len < (vndrie_info->vndrie.len +
3382 VNDR_IE_VSIE_OFFSET)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003383 brcmf_err("no space in mgmt_ie_buf: len left %d",
3384 remained_buf_len);
Hante Meulemanb41fc3d2012-11-28 21:44:13 +01003385 break;
3386 }
3387 remained_buf_len -= (vndrie_info->ie_len +
3388 VNDR_IE_VSIE_OFFSET);
3389
Arend van Sprield96b8012012-12-05 15:26:02 +01003390 brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
3391 vndrie_info->vndrie.id,
3392 vndrie_info->vndrie.len,
3393 vndrie_info->vndrie.oui[0],
3394 vndrie_info->vndrie.oui[1],
3395 vndrie_info->vndrie.oui[2]);
Hante Meuleman1a873342012-09-27 14:17:54 +02003396
3397 del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
3398 vndrie_info->ie_ptr,
3399 vndrie_info->ie_len,
3400 "add");
Hante Meuleman1a873342012-09-27 14:17:54 +02003401
3402 /* save the parsed IE in wl struct */
3403 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
3404 vndrie_info->ie_len);
3405 *mgmt_ie_len += vndrie_info->ie_len;
3406
3407 curr_ie_buf += del_add_ie_buf_len;
3408 total_ie_buf_len += del_add_ie_buf_len;
3409 }
3410 }
3411 if (total_ie_buf_len) {
Arend van Sprielc1179032012-10-22 13:55:33 -07003412 err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003413 total_ie_buf_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003414 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003415 brcmf_err("vndr ie set error : %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003416 }
3417
3418exit:
3419 kfree(iovar_ie_buf);
3420 return err;
3421}
3422
3423static s32
3424brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3425 struct cfg80211_ap_settings *settings)
3426{
3427 s32 ie_offset;
Arend van Sprielac24be62012-10-22 10:36:23 -07003428 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003429 struct brcmf_tlv *ssid_ie;
3430 struct brcmf_ssid_le ssid_le;
Hante Meuleman1a873342012-09-27 14:17:54 +02003431 s32 err = -EPERM;
3432 struct brcmf_tlv *rsn_ie;
3433 struct brcmf_vs_tlv *wpa_ie;
3434 struct brcmf_join_params join_params;
Hante Meuleman1a873342012-09-27 14:17:54 +02003435
Arend van Sprield96b8012012-12-05 15:26:02 +01003436 brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
3437 cfg80211_get_chandef_type(&settings->chandef),
3438 settings->beacon_interval,
3439 settings->dtim_period);
3440 brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
3441 settings->ssid, settings->ssid_len, settings->auth_type,
3442 settings->inactivity_timeout);
Hante Meuleman1a873342012-09-27 14:17:54 +02003443
Arend van Sprielc1179032012-10-22 13:55:33 -07003444 if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003445 brcmf_err("Not in AP creation mode\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003446 return -EPERM;
3447 }
3448
3449 memset(&ssid_le, 0, sizeof(ssid_le));
3450 if (settings->ssid == NULL || settings->ssid_len == 0) {
3451 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3452 ssid_ie = brcmf_parse_tlvs(
3453 (u8 *)&settings->beacon.head[ie_offset],
3454 settings->beacon.head_len - ie_offset,
3455 WLAN_EID_SSID);
3456 if (!ssid_ie)
3457 return -EINVAL;
3458
3459 memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
3460 ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
Arend van Sprield96b8012012-12-05 15:26:02 +01003461 brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
Hante Meuleman1a873342012-09-27 14:17:54 +02003462 } else {
3463 memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
3464 ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
3465 }
3466
3467 brcmf_set_mpc(ndev, 0);
Arend van Sprielac24be62012-10-22 10:36:23 -07003468 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003469 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003470 brcmf_err("BRCMF_C_DOWN error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003471 goto exit;
3472 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003473 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003474 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003475 brcmf_err("SET INFRA error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003476 goto exit;
3477 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003478 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003479 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003480 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003481 goto exit;
3482 }
3483
3484 /* find the RSN_IE */
3485 rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
3486 settings->beacon.tail_len, WLAN_EID_RSN);
3487
3488 /* find the WPA_IE */
3489 wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
3490 settings->beacon.tail_len);
3491
Hante Meuleman1a873342012-09-27 14:17:54 +02003492 if ((wpa_ie != NULL || rsn_ie != NULL)) {
Arend van Sprield96b8012012-12-05 15:26:02 +01003493 brcmf_dbg(TRACE, "WPA(2) IE is found\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003494 if (wpa_ie != NULL) {
3495 /* WPA IE */
Arend van Spriel34778522012-11-05 16:22:19 -08003496 err = brcmf_configure_wpaie(ndev, wpa_ie, false);
Hante Meuleman1a873342012-09-27 14:17:54 +02003497 if (err < 0)
3498 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003499 } else {
3500 /* RSN IE */
3501 err = brcmf_configure_wpaie(ndev,
Arend van Spriel34778522012-11-05 16:22:19 -08003502 (struct brcmf_vs_tlv *)rsn_ie, true);
Hante Meuleman1a873342012-09-27 14:17:54 +02003503 if (err < 0)
3504 goto exit;
Hante Meuleman1a873342012-09-27 14:17:54 +02003505 }
Hante Meuleman1a873342012-09-27 14:17:54 +02003506 } else {
Arend van Sprield96b8012012-12-05 15:26:02 +01003507 brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
Hante Meuleman1f170112013-02-06 18:40:38 +01003508 brcmf_configure_opensecurity(ifp);
Hante Meuleman1a873342012-09-27 14:17:54 +02003509 }
3510 /* Set Beacon IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003511 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
3512 VNDR_IE_BEACON_FLAG,
3513 settings->beacon.tail,
3514 settings->beacon.tail_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003515 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003516 brcmf_err("Set Beacon IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003517 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003518 brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003519
3520 /* Set Probe Response IEs to FW */
Arend van Spriel1332e262012-11-05 16:22:18 -08003521 err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
3522 VNDR_IE_PRBRSP_FLAG,
3523 settings->beacon.proberesp_ies,
3524 settings->beacon.proberesp_ies_len);
Hante Meuleman1a873342012-09-27 14:17:54 +02003525 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003526 brcmf_err("Set Probe Resp IE Failed\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003527 else
Arend van Sprield96b8012012-12-05 15:26:02 +01003528 brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003529
3530 if (settings->beacon_interval) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003531 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003532 settings->beacon_interval);
Hante Meuleman1a873342012-09-27 14:17:54 +02003533 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003534 brcmf_err("Beacon Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003535 goto exit;
3536 }
3537 }
3538 if (settings->dtim_period) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003539 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003540 settings->dtim_period);
Hante Meuleman1a873342012-09-27 14:17:54 +02003541 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003542 brcmf_err("DTIM Interval Set Error, %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003543 goto exit;
3544 }
3545 }
Arend van Sprielac24be62012-10-22 10:36:23 -07003546 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
Hante Meuleman1a873342012-09-27 14:17:54 +02003547 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003548 brcmf_err("BRCMF_C_UP error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003549 goto exit;
3550 }
3551
3552 memset(&join_params, 0, sizeof(join_params));
3553 /* join parameters starts with ssid */
3554 memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
3555 /* create softap */
Arend van Sprielac24be62012-10-22 10:36:23 -07003556 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
3557 &join_params, sizeof(join_params));
Hante Meuleman1a873342012-09-27 14:17:54 +02003558 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003559 brcmf_err("SET SSID error (%d)\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003560 goto exit;
3561 }
Arend van Sprielc1179032012-10-22 13:55:33 -07003562 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3563 set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003564
3565exit:
3566 if (err)
3567 brcmf_set_mpc(ndev, 1);
3568 return err;
3569}
3570
3571static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3572{
Arend van Sprielc1179032012-10-22 13:55:33 -07003573 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003574 s32 err = -EPERM;
3575
Arend van Sprield96b8012012-12-05 15:26:02 +01003576 brcmf_dbg(TRACE, "Enter\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003577
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003578 if (ifp->vif->mode == WL_MODE_AP) {
Hante Meuleman1a873342012-09-27 14:17:54 +02003579 /* Due to most likely deauths outstanding we sleep */
3580 /* first to make sure they get processed by fw. */
3581 msleep(400);
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003582 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003583 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003584 brcmf_err("setting AP mode failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003585 goto exit;
3586 }
Arend van Spriel128ce3b2012-11-28 21:44:12 +01003587 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
Hante Meuleman1a873342012-09-27 14:17:54 +02003588 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003589 brcmf_err("BRCMF_C_UP error %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003590 goto exit;
3591 }
3592 brcmf_set_mpc(ndev, 1);
Arend van Sprielc1179032012-10-22 13:55:33 -07003593 clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
3594 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
Hante Meuleman1a873342012-09-27 14:17:54 +02003595 }
3596exit:
3597 return err;
3598}
3599
3600static int
3601brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3602 u8 *mac)
3603{
3604 struct brcmf_scb_val_le scbval;
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003605 struct brcmf_if *ifp = netdev_priv(ndev);
Hante Meuleman1a873342012-09-27 14:17:54 +02003606 s32 err;
3607
3608 if (!mac)
3609 return -EFAULT;
3610
Arend van Sprield96b8012012-12-05 15:26:02 +01003611 brcmf_dbg(TRACE, "Enter %pM\n", mac);
Hante Meuleman1a873342012-09-27 14:17:54 +02003612
Arend van Sprielce81e312012-10-22 13:55:37 -07003613 if (!check_vif_up(ifp->vif))
Hante Meuleman1a873342012-09-27 14:17:54 +02003614 return -EIO;
3615
3616 memcpy(&scbval.ea, mac, ETH_ALEN);
3617 scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
Arend van Spriel0abb5f212012-10-22 13:55:32 -07003618 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003619 &scbval, sizeof(scbval));
Hante Meuleman1a873342012-09-27 14:17:54 +02003620 if (err)
Arend van Spriel57d6e912012-12-05 15:26:00 +01003621 brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
Hante Meuleman1a873342012-09-27 14:17:54 +02003622
Arend van Sprield96b8012012-12-05 15:26:02 +01003623 brcmf_dbg(TRACE, "Exit\n");
Hante Meuleman1a873342012-09-27 14:17:54 +02003624 return err;
3625}
3626
Arend van Spriel5b435de2011-10-05 13:19:03 +02003627static struct cfg80211_ops wl_cfg80211_ops = {
3628 .change_virtual_intf = brcmf_cfg80211_change_iface,
3629 .scan = brcmf_cfg80211_scan,
3630 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
3631 .join_ibss = brcmf_cfg80211_join_ibss,
3632 .leave_ibss = brcmf_cfg80211_leave_ibss,
3633 .get_station = brcmf_cfg80211_get_station,
3634 .set_tx_power = brcmf_cfg80211_set_tx_power,
3635 .get_tx_power = brcmf_cfg80211_get_tx_power,
3636 .add_key = brcmf_cfg80211_add_key,
3637 .del_key = brcmf_cfg80211_del_key,
3638 .get_key = brcmf_cfg80211_get_key,
3639 .set_default_key = brcmf_cfg80211_config_default_key,
3640 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
3641 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003642 .connect = brcmf_cfg80211_connect,
3643 .disconnect = brcmf_cfg80211_disconnect,
3644 .suspend = brcmf_cfg80211_suspend,
3645 .resume = brcmf_cfg80211_resume,
3646 .set_pmksa = brcmf_cfg80211_set_pmksa,
3647 .del_pmksa = brcmf_cfg80211_del_pmksa,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003648 .flush_pmksa = brcmf_cfg80211_flush_pmksa,
Hante Meuleman1a873342012-09-27 14:17:54 +02003649 .start_ap = brcmf_cfg80211_start_ap,
3650 .stop_ap = brcmf_cfg80211_stop_ap,
3651 .del_station = brcmf_cfg80211_del_station,
Arend van Spriele5806072012-09-19 22:21:08 +02003652 .sched_scan_start = brcmf_cfg80211_sched_scan_start,
3653 .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
Arend van Sprielcbaa1772012-08-30 19:43:02 +02003654#ifdef CONFIG_NL80211_TESTMODE
3655 .testmode_cmd = brcmf_cfg80211_testmode
3656#endif
Arend van Spriel5b435de2011-10-05 13:19:03 +02003657};
3658
3659static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
3660{
3661 s32 err = 0;
3662
3663 switch (mode) {
3664 case WL_MODE_BSS:
3665 return NL80211_IFTYPE_STATION;
3666 case WL_MODE_IBSS:
3667 return NL80211_IFTYPE_ADHOC;
3668 default:
3669 return NL80211_IFTYPE_UNSPECIFIED;
3670 }
3671
3672 return err;
3673}
3674
Arend van Spriele5806072012-09-19 22:21:08 +02003675static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
3676{
Arend van Spriele5806072012-09-19 22:21:08 +02003677 /* scheduled scan settings */
3678 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
3679 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
3680 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
3681 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
Arend van Spriele5806072012-09-19 22:21:08 +02003682}
3683
Arend van Spriel3eacf862012-10-22 13:55:30 -07003684static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003685{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003686 struct wiphy *wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003687 s32 err = 0;
3688
Arend van Spriel3eacf862012-10-22 13:55:30 -07003689 wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
3690 if (!wiphy) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003691 brcmf_err("Could not allocate wiphy device\n");
Arend van Spriel3eacf862012-10-22 13:55:30 -07003692 return ERR_PTR(-ENOMEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003693 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003694 set_wiphy_dev(wiphy, phydev);
3695 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
3696 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
3697 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3698 BIT(NL80211_IFTYPE_ADHOC) |
3699 BIT(NL80211_IFTYPE_AP);
3700 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
3701 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
Arend van Spriel5b435de2011-10-05 13:19:03 +02003702 * it as 11a by default.
3703 * This will be updated with
3704 * 11n phy tables in
3705 * "ifconfig up"
3706 * if phy has 11n capability
3707 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07003708 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3709 wiphy->cipher_suites = __wl_cipher_suites;
3710 wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
3711 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
Arend van Spriel5b435de2011-10-05 13:19:03 +02003712 * save mode
3713 * by default
3714 */
Arend van Spriel3eacf862012-10-22 13:55:30 -07003715 brcmf_wiphy_pno_params(wiphy);
3716 err = wiphy_register(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003717 if (err < 0) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003718 brcmf_err("Could not register wiphy device (%d)\n", err);
Arend van Spriel3eacf862012-10-22 13:55:30 -07003719 wiphy_free(wiphy);
3720 return ERR_PTR(err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003721 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003722 return wiphy;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003723}
3724
Arend van Spriel3eacf862012-10-22 13:55:30 -07003725static
3726struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
3727 struct net_device *netdev,
3728 s32 mode, bool pm_block)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003729{
Arend van Spriel3eacf862012-10-22 13:55:30 -07003730 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003731
Arend van Spriel3eacf862012-10-22 13:55:30 -07003732 if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
3733 return ERR_PTR(-ENOSPC);
3734
3735 vif = kzalloc(sizeof(*vif), GFP_KERNEL);
3736 if (!vif)
3737 return ERR_PTR(-ENOMEM);
3738
3739 vif->wdev.wiphy = cfg->wiphy;
3740 vif->wdev.netdev = netdev;
3741 vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
3742
3743 if (netdev) {
3744 vif->ifp = netdev_priv(netdev);
3745 netdev->ieee80211_ptr = &vif->wdev;
3746 SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003747 }
Arend van Spriel3eacf862012-10-22 13:55:30 -07003748
3749 vif->mode = mode;
3750 vif->pm_block = pm_block;
3751 vif->roam_off = -1;
3752
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07003753 brcmf_init_prof(&vif->profile);
3754
Arend van Spriel3eacf862012-10-22 13:55:30 -07003755 list_add_tail(&vif->list, &cfg->vif_list);
3756 cfg->vif_cnt++;
3757 return vif;
3758}
3759
3760static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
3761{
3762 struct brcmf_cfg80211_info *cfg;
3763 struct wiphy *wiphy;
3764
3765 wiphy = vif->wdev.wiphy;
3766 cfg = wiphy_priv(wiphy);
3767 list_del(&vif->list);
3768 cfg->vif_cnt--;
3769
3770 kfree(vif);
3771 if (!cfg->vif_cnt) {
3772 wiphy_unregister(wiphy);
3773 wiphy_free(wiphy);
3774 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003775}
3776
Arend van Spriel903e0ee2012-11-28 21:44:11 +01003777static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003778{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003779 u32 event = e->event_code;
3780 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003781
3782 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01003783 brcmf_dbg(CONN, "Processing set ssid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003784 return true;
3785 }
3786
3787 return false;
3788}
3789
Arend van Spriel903e0ee2012-11-28 21:44:11 +01003790static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003791{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003792 u32 event = e->event_code;
3793 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003794
3795 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
Arend van Spriel16886732012-12-05 15:26:04 +01003796 brcmf_dbg(CONN, "Processing link down\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003797 return true;
3798 }
3799 return false;
3800}
3801
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003802static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003803 const struct brcmf_event_msg *e)
3804{
Arend van Spriel5c36b992012-11-14 18:46:05 -08003805 u32 event = e->event_code;
3806 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003807
3808 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
Arend van Spriel16886732012-12-05 15:26:04 +01003809 brcmf_dbg(CONN, "Processing Link %s & no network found\n",
3810 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003811 return true;
3812 }
3813
3814 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
Arend van Spriel16886732012-12-05 15:26:04 +01003815 brcmf_dbg(CONN, "Processing connecting & no network found\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003816 return true;
3817 }
3818
3819 return false;
3820}
3821
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003822static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003823{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003824 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003825
3826 kfree(conn_info->req_ie);
3827 conn_info->req_ie = NULL;
3828 conn_info->req_ie_len = 0;
3829 kfree(conn_info->resp_ie);
3830 conn_info->resp_ie = NULL;
3831 conn_info->resp_ie_len = 0;
3832}
3833
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003834static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003835{
Arend van Sprielac24be62012-10-22 10:36:23 -07003836 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Sprielc4e382d2011-10-12 20:51:21 +02003837 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003838 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003839 u32 req_len;
3840 u32 resp_len;
3841 s32 err = 0;
3842
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003843 brcmf_clear_assoc_ies(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003844
Arend van Sprielac24be62012-10-22 10:36:23 -07003845 err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
3846 cfg->extra_buf, WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003847 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003848 brcmf_err("could not get assoc info (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003849 return err;
3850 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02003851 assoc_info =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003852 (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
Arend van Sprielc4e382d2011-10-12 20:51:21 +02003853 req_len = le32_to_cpu(assoc_info->req_len);
3854 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003855 if (req_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003856 err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003857 cfg->extra_buf,
3858 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003859 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003860 brcmf_err("could not get assoc req (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003861 return err;
3862 }
3863 conn_info->req_ie_len = req_len;
3864 conn_info->req_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003865 kmemdup(cfg->extra_buf, conn_info->req_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003866 GFP_KERNEL);
3867 } else {
3868 conn_info->req_ie_len = 0;
3869 conn_info->req_ie = NULL;
3870 }
3871 if (resp_len) {
Arend van Sprielac24be62012-10-22 10:36:23 -07003872 err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07003873 cfg->extra_buf,
3874 WL_ASSOC_INFO_MAX);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003875 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01003876 brcmf_err("could not get assoc resp (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003877 return err;
3878 }
3879 conn_info->resp_ie_len = resp_len;
3880 conn_info->resp_ie =
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003881 kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003882 GFP_KERNEL);
3883 } else {
3884 conn_info->resp_ie_len = 0;
3885 conn_info->resp_ie = NULL;
3886 }
Arend van Spriel16886732012-12-05 15:26:04 +01003887 brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
3888 conn_info->req_ie_len, conn_info->resp_ie_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003889
3890 return err;
3891}
3892
3893static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003894brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003895 struct net_device *ndev,
3896 const struct brcmf_event_msg *e)
3897{
Arend van Sprielc1179032012-10-22 13:55:33 -07003898 struct brcmf_if *ifp = netdev_priv(ndev);
3899 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003900 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
3901 struct wiphy *wiphy = cfg_to_wiphy(cfg);
Franky Lina180b832012-10-10 11:13:09 -07003902 struct ieee80211_channel *notify_channel = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003903 struct ieee80211_supported_band *band;
Franky Lina180b832012-10-10 11:13:09 -07003904 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003905 u32 freq;
3906 s32 err = 0;
3907 u32 target_channel;
Franky Lina180b832012-10-10 11:13:09 -07003908 u8 *buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003909
Arend van Sprield96b8012012-12-05 15:26:02 +01003910 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003911
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003912 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02003913 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003914 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003915
Franky Lina180b832012-10-10 11:13:09 -07003916 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
3917 if (buf == NULL) {
3918 err = -ENOMEM;
3919 goto done;
3920 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003921
Franky Lina180b832012-10-10 11:13:09 -07003922 /* data sent to dongle has to be little endian */
3923 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
Arend van Sprielc1179032012-10-22 13:55:33 -07003924 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
Arend van Sprielac24be62012-10-22 10:36:23 -07003925 buf, WL_BSS_INFO_MAX);
Franky Lina180b832012-10-10 11:13:09 -07003926
3927 if (err)
3928 goto done;
3929
3930 bi = (struct brcmf_bss_info_le *)(buf + 4);
3931 target_channel = bi->ctl_ch ? bi->ctl_ch :
3932 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003933
3934 if (target_channel <= CH_MAX_2G_CHANNEL)
3935 band = wiphy->bands[IEEE80211_BAND_2GHZ];
3936 else
3937 band = wiphy->bands[IEEE80211_BAND_5GHZ];
3938
3939 freq = ieee80211_channel_to_frequency(target_channel, band->band);
3940 notify_channel = ieee80211_get_channel(wiphy, freq);
3941
Franky Lina180b832012-10-10 11:13:09 -07003942done:
3943 kfree(buf);
Arend van Spriel06bb1232012-09-27 14:17:56 +02003944 cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003945 conn_info->req_ie, conn_info->req_ie_len,
3946 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
Arend van Spriel16886732012-12-05 15:26:04 +01003947 brcmf_dbg(CONN, "Report roaming result\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003948
Arend van Sprielc1179032012-10-22 13:55:33 -07003949 set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
Arend van Sprield96b8012012-12-05 15:26:02 +01003950 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003951 return err;
3952}
3953
3954static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003955brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003956 struct net_device *ndev, const struct brcmf_event_msg *e,
3957 bool completed)
3958{
Arend van Sprielc1179032012-10-22 13:55:33 -07003959 struct brcmf_if *ifp = netdev_priv(ndev);
3960 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003961 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003962 s32 err = 0;
3963
Arend van Sprield96b8012012-12-05 15:26:02 +01003964 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003965
Arend van Sprielc1179032012-10-22 13:55:33 -07003966 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
3967 &ifp->vif->sme_state)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003968 if (completed) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003969 brcmf_get_assoc_ies(cfg);
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02003970 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003971 brcmf_update_bss_info(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003972 }
3973 cfg80211_connect_result(ndev,
Arend van Spriel06bb1232012-09-27 14:17:56 +02003974 (u8 *)profile->bssid,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003975 conn_info->req_ie,
3976 conn_info->req_ie_len,
3977 conn_info->resp_ie,
3978 conn_info->resp_ie_len,
3979 completed ? WLAN_STATUS_SUCCESS :
3980 WLAN_STATUS_AUTH_TIMEOUT,
3981 GFP_KERNEL);
3982 if (completed)
Arend van Sprielc1179032012-10-22 13:55:33 -07003983 set_bit(BRCMF_VIF_STATUS_CONNECTED,
3984 &ifp->vif->sme_state);
Arend van Spriel16886732012-12-05 15:26:04 +01003985 brcmf_dbg(CONN, "Report connect result - connection %s\n",
3986 completed ? "succeeded" : "failed");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003987 }
Arend van Sprield96b8012012-12-05 15:26:02 +01003988 brcmf_dbg(TRACE, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003989 return err;
3990}
3991
3992static s32
Arend van Spriel27a68fe2012-09-27 14:17:55 +02003993brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
Hante Meuleman1a873342012-09-27 14:17:54 +02003994 struct net_device *ndev,
3995 const struct brcmf_event_msg *e, void *data)
3996{
3997 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08003998 u32 event = e->event_code;
3999 u32 reason = e->reason;
4000 u32 len = e->datalen;
Hante Meuleman1a873342012-09-27 14:17:54 +02004001 static int generation;
4002
4003 struct station_info sinfo;
4004
Arend van Spriel16886732012-12-05 15:26:04 +01004005 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
Hante Meuleman1a873342012-09-27 14:17:54 +02004006 memset(&sinfo, 0, sizeof(sinfo));
4007
4008 sinfo.filled = 0;
4009 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4010 reason == BRCMF_E_STATUS_SUCCESS) {
4011 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
4012 if (!data) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004013 brcmf_err("No IEs present in ASSOC/REASSOC_IND");
Hante Meuleman1a873342012-09-27 14:17:54 +02004014 return -EINVAL;
4015 }
4016 sinfo.assoc_req_ies = data;
4017 sinfo.assoc_req_ies_len = len;
4018 generation++;
4019 sinfo.generation = generation;
4020 cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
4021 } else if ((event == BRCMF_E_DISASSOC_IND) ||
4022 (event == BRCMF_E_DEAUTH_IND) ||
4023 (event == BRCMF_E_DEAUTH)) {
4024 generation++;
4025 sinfo.generation = generation;
4026 cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
4027 }
4028 return err;
4029}
4030
4031static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004032brcmf_notify_connect_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004033 const struct brcmf_event_msg *e, void *data)
4034{
Arend van Spriel19937322012-11-05 16:22:32 -08004035 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4036 struct net_device *ndev = ifp->ndev;
Arend van Sprielc1179032012-10-22 13:55:33 -07004037 struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004038 s32 err = 0;
4039
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004040 if (ifp->vif->mode == WL_MODE_AP) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004041 err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004042 } else if (brcmf_is_linkup(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004043 brcmf_dbg(CONN, "Linkup\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004044 if (brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel6c8c4f72012-09-27 14:17:57 +02004045 memcpy(profile->bssid, e->addr, ETH_ALEN);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004046 wl_inform_ibss(cfg, ndev, e->addr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004047 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
Arend van Sprielc1179032012-10-22 13:55:33 -07004048 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4049 &ifp->vif->sme_state);
4050 set_bit(BRCMF_VIF_STATUS_CONNECTED,
4051 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004052 } else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004053 brcmf_bss_connect_done(cfg, ndev, e, true);
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004054 } else if (brcmf_is_linkdown(e)) {
Arend van Spriel16886732012-12-05 15:26:04 +01004055 brcmf_dbg(CONN, "Linkdown\n");
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004056 if (!brcmf_is_ibssmode(ifp->vif)) {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004057 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Sprielc1179032012-10-22 13:55:33 -07004058 if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004059 &ifp->vif->sme_state))
Arend van Spriel5b435de2011-10-05 13:19:03 +02004060 cfg80211_disconnected(ndev, 0, NULL, 0,
Arend van Sprielc1179032012-10-22 13:55:33 -07004061 GFP_KERNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004062 }
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004063 brcmf_link_down(ifp->vif);
Arend van Spriel6ac4f4e2012-10-22 13:55:31 -07004064 brcmf_init_prof(ndev_to_prof(ndev));
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004065 } else if (brcmf_is_nonetwork(cfg, e)) {
Arend van Spriel128ce3b2012-11-28 21:44:12 +01004066 if (brcmf_is_ibssmode(ifp->vif))
Arend van Sprielc1179032012-10-22 13:55:33 -07004067 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
4068 &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004069 else
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004070 brcmf_bss_connect_done(cfg, ndev, e, false);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004071 }
4072
4073 return err;
4074}
4075
4076static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004077brcmf_notify_roaming_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004078 const struct brcmf_event_msg *e, void *data)
4079{
Arend van Spriel19937322012-11-05 16:22:32 -08004080 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004081 s32 err = 0;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004082 u32 event = e->event_code;
4083 u32 status = e->status;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004084
4085 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
Arend van Sprielc1179032012-10-22 13:55:33 -07004086 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
Arend van Spriel19937322012-11-05 16:22:32 -08004087 brcmf_bss_roaming_done(cfg, ifp->ndev, e);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004088 else
Arend van Spriel19937322012-11-05 16:22:32 -08004089 brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004090 }
4091
4092 return err;
4093}
4094
4095static s32
Arend van Spriel19937322012-11-05 16:22:32 -08004096brcmf_notify_mic_status(struct brcmf_if *ifp,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004097 const struct brcmf_event_msg *e, void *data)
4098{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004099 u16 flags = e->flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004100 enum nl80211_key_type key_type;
4101
4102 if (flags & BRCMF_EVENT_MSG_GROUP)
4103 key_type = NL80211_KEYTYPE_GROUP;
4104 else
4105 key_type = NL80211_KEYTYPE_PAIRWISE;
4106
Arend van Spriel19937322012-11-05 16:22:32 -08004107 cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
Arend van Spriel5b435de2011-10-05 13:19:03 +02004108 NULL, GFP_KERNEL);
4109
4110 return 0;
4111}
4112
Arend van Spriel5b435de2011-10-05 13:19:03 +02004113static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4114{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004115 conf->frag_threshold = (u32)-1;
4116 conf->rts_threshold = (u32)-1;
4117 conf->retry_short = (u32)-1;
4118 conf->retry_long = (u32)-1;
4119 conf->tx_power = -1;
4120}
4121
Arend van Spriel5c36b992012-11-14 18:46:05 -08004122static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004123{
Arend van Spriel5c36b992012-11-14 18:46:05 -08004124 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4125 brcmf_notify_connect_status);
4126 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4127 brcmf_notify_connect_status);
4128 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4129 brcmf_notify_connect_status);
4130 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4131 brcmf_notify_connect_status);
4132 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4133 brcmf_notify_connect_status);
4134 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4135 brcmf_notify_connect_status);
4136 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4137 brcmf_notify_roaming_status);
4138 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4139 brcmf_notify_mic_status);
4140 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4141 brcmf_notify_connect_status);
4142 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4143 brcmf_notify_sched_scan_results);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004144}
4145
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004146static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004147{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004148 kfree(cfg->conf);
4149 cfg->conf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004150 kfree(cfg->escan_ioctl_buf);
4151 cfg->escan_ioctl_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004152 kfree(cfg->extra_buf);
4153 cfg->extra_buf = NULL;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004154 kfree(cfg->pmk_list);
4155 cfg->pmk_list = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004156}
4157
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004158static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004159{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004160 cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
4161 if (!cfg->conf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004162 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004163 cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
4164 if (!cfg->escan_ioctl_buf)
Hante Meulemane756af52012-09-11 21:18:52 +02004165 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004166 cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
4167 if (!cfg->extra_buf)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004168 goto init_priv_mem_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004169 cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
4170 if (!cfg->pmk_list)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004171 goto init_priv_mem_out;
4172
4173 return 0;
4174
4175init_priv_mem_out:
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004176 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004177
4178 return -ENOMEM;
4179}
4180
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004181static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004182{
4183 s32 err = 0;
4184
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004185 cfg->scan_request = NULL;
4186 cfg->pwr_save = true;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004187 cfg->roam_on = true; /* roam on & off switch.
Arend van Spriel5b435de2011-10-05 13:19:03 +02004188 we enable roam per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004189 cfg->active_scan = true; /* we do active scan for
Arend van Spriel5b435de2011-10-05 13:19:03 +02004190 specific scan per default */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004191 cfg->dongle_up = false; /* dongle is not up yet */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004192 err = brcmf_init_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004193 if (err)
4194 return err;
Arend van Spriel5c36b992012-11-14 18:46:05 -08004195 brcmf_register_event_handlers(cfg);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004196 mutex_init(&cfg->usr_sync);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004197 brcmf_init_escan(cfg);
4198 brcmf_init_conf(cfg->conf);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004199
4200 return err;
4201}
4202
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004203static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004204{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004205 cfg->dongle_up = false; /* dongle down */
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004206 brcmf_abort_scanning(cfg);
4207 brcmf_deinit_priv_mem(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004208}
4209
Arend van Sprield9cb2592012-12-05 15:25:54 +01004210struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
4211 struct device *busdev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004212{
Arend van Spriel1ed9baf2012-10-22 10:36:20 -07004213 struct net_device *ndev = drvr->iflist[0]->ndev;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004214 struct brcmf_cfg80211_info *cfg;
Arend van Spriel3eacf862012-10-22 13:55:30 -07004215 struct wiphy *wiphy;
4216 struct brcmf_cfg80211_vif *vif;
4217 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004218 s32 err = 0;
4219
4220 if (!ndev) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004221 brcmf_err("ndev is invalid\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004222 return NULL;
4223 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004224
Arend van Spriel3eacf862012-10-22 13:55:30 -07004225 ifp = netdev_priv(ndev);
4226 wiphy = brcmf_setup_wiphy(busdev);
4227 if (IS_ERR(wiphy))
4228 return NULL;
4229
4230 cfg = wiphy_priv(wiphy);
4231 cfg->wiphy = wiphy;
4232 cfg->pub = drvr;
4233 INIT_LIST_HEAD(&cfg->vif_list);
4234
4235 vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
4236 if (IS_ERR(vif)) {
4237 wiphy_free(wiphy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004238 return NULL;
4239 }
4240
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004241 err = wl_init_priv(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004242 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004243 brcmf_err("Failed to init iwm_priv (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004244 goto cfg80211_attach_out;
4245 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004246
Arend van Spriel3eacf862012-10-22 13:55:30 -07004247 ifp->vif = vif;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004248 return cfg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004249
4250cfg80211_attach_out:
Arend van Spriel3eacf862012-10-22 13:55:30 -07004251 brcmf_free_vif(vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004252 return NULL;
4253}
4254
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004255void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004256{
Arend van Spriel3eacf862012-10-22 13:55:30 -07004257 struct brcmf_cfg80211_vif *vif;
4258 struct brcmf_cfg80211_vif *tmp;
4259
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004260 wl_deinit_priv(cfg);
Arend van Spriel3eacf862012-10-22 13:55:30 -07004261 list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
4262 brcmf_free_vif(vif);
4263 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02004264}
4265
Arend van Spriel5b435de2011-10-05 13:19:03 +02004266static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004267brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004268{
Arend van Spriel5b435de2011-10-05 13:19:03 +02004269 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02004270 __le32 roamtrigger[2];
4271 __le32 roam_delta[2];
Arend van Spriel5b435de2011-10-05 13:19:03 +02004272
4273 /*
4274 * Setup timeout if Beacons are lost and roam is
4275 * off to report link down
4276 */
4277 if (roamvar) {
Arend van Sprielac24be62012-10-22 10:36:23 -07004278 err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004279 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004280 brcmf_err("bcn_timeout error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004281 goto dongle_rom_out;
4282 }
4283 }
4284
4285 /*
4286 * Enable/Disable built-in roaming to allow supplicant
4287 * to take care of roaming
4288 */
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004289 brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielac24be62012-10-22 10:36:23 -07004290 err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004291 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004292 brcmf_err("roam_off error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004293 goto dongle_rom_out;
4294 }
4295
Arend van Sprielf588bc02011-10-12 20:51:22 +02004296 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
4297 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004298 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004299 (void *)roamtrigger, sizeof(roamtrigger));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004300 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004301 brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004302 goto dongle_rom_out;
4303 }
4304
Arend van Sprielf588bc02011-10-12 20:51:22 +02004305 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
4306 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Sprielac24be62012-10-22 10:36:23 -07004307 err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004308 (void *)roam_delta, sizeof(roam_delta));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004309 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004310 brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004311 goto dongle_rom_out;
4312 }
4313
4314dongle_rom_out:
4315 return err;
4316}
4317
4318static s32
Hante Meuleman40a23292013-01-02 15:22:51 +01004319brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02004320 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004321{
4322 s32 err = 0;
4323
Arend van Sprielac24be62012-10-22 10:36:23 -07004324 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004325 scan_assoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004326 if (err) {
4327 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004328 brcmf_dbg(INFO, "Scan assoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004329 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004330 brcmf_err("Scan assoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004331 goto dongle_scantime_out;
4332 }
Arend van Sprielac24be62012-10-22 10:36:23 -07004333 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004334 scan_unassoc_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004335 if (err) {
4336 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004337 brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004338 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004339 brcmf_err("Scan unassoc time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004340 goto dongle_scantime_out;
4341 }
4342
Arend van Sprielac24be62012-10-22 10:36:23 -07004343 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004344 scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004345 if (err) {
4346 if (err == -EOPNOTSUPP)
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004347 brcmf_dbg(INFO, "Scan passive time is not supported\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02004348 else
Arend van Spriel57d6e912012-12-05 15:26:00 +01004349 brcmf_err("Scan passive time error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004350 goto dongle_scantime_out;
4351 }
4352
4353dongle_scantime_out:
4354 return err;
4355}
4356
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004357static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004358{
Arend van Sprielac24be62012-10-22 10:36:23 -07004359 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004360 struct wiphy *wiphy;
4361 s32 phy_list;
4362 s8 phy;
4363 s32 err = 0;
4364
Hante Meulemanb87e2c42012-11-14 18:46:23 -08004365 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
Hante Meuleman81f5dcb2012-10-22 10:36:14 -07004366 &phy_list, sizeof(phy_list));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004367 if (err) {
Arend van Spriel57d6e912012-12-05 15:26:00 +01004368 brcmf_err("error (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004369 return err;
4370 }
4371
Hante Meuleman3ba81372012-09-19 22:21:13 +02004372 phy = ((char *)&phy_list)[0];
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004373 brcmf_dbg(INFO, "%c phy\n", phy);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004374 if (phy == 'n' || phy == 'a') {
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004375 wiphy = cfg_to_wiphy(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004376 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4377 }
4378
4379 return err;
4380}
4381
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004382static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004383{
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004384 return wl_update_wiphybands(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004385}
4386
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004387static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004388{
4389 struct net_device *ndev;
4390 struct wireless_dev *wdev;
Hante Meuleman40a23292013-01-02 15:22:51 +01004391 struct brcmf_if *ifp;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004392 s32 power_mode;
4393 s32 err = 0;
4394
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004395 if (cfg->dongle_up)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004396 return err;
4397
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004398 ndev = cfg_to_ndev(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004399 wdev = ndev->ieee80211_ptr;
Hante Meuleman40a23292013-01-02 15:22:51 +01004400 ifp = netdev_priv(ndev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004401
Hante Meuleman40a23292013-01-02 15:22:51 +01004402 /* make sure RF is ready for work */
4403 brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
4404
4405 brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
4406 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004407
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004408 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
Hante Meuleman40a23292013-01-02 15:22:51 +01004409 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004410 if (err)
4411 goto default_conf_out;
Arend van Spriel647c9ae2012-12-05 15:26:01 +01004412 brcmf_dbg(INFO, "power save set to %s\n",
4413 (power_mode ? "enabled" : "disabled"));
Arend van Spriel5b435de2011-10-05 13:19:03 +02004414
Hante Meuleman40a23292013-01-02 15:22:51 +01004415 err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004416 if (err)
4417 goto default_conf_out;
Franky Lin5dd161f2012-10-10 11:13:10 -07004418 err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
4419 NULL, NULL);
Hante Meuleman40a23292013-01-02 15:22:51 +01004420 if (err)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004421 goto default_conf_out;
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004422 err = brcmf_dongle_probecap(cfg);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004423 if (err)
4424 goto default_conf_out;
4425
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004426 cfg->dongle_up = true;
Hante Meuleman40a23292013-01-02 15:22:51 +01004427default_conf_out:
Arend van Spriel5b435de2011-10-05 13:19:03 +02004428
4429 return err;
4430
4431}
4432
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004433static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004434{
Arend van Sprielc1179032012-10-22 13:55:33 -07004435 set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004436
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004437 return brcmf_config_dongle(ifp->drvr->config);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004438}
4439
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004440static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004441{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004442 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Sprielc1179032012-10-22 13:55:33 -07004443
Arend van Spriel5b435de2011-10-05 13:19:03 +02004444 /*
4445 * While going down, if associated with AP disassociate
4446 * from AP to save power
4447 */
Arend van Spriel903e0ee2012-11-28 21:44:11 +01004448 if (check_vif_up(ifp->vif)) {
4449 brcmf_link_down(ifp->vif);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004450
4451 /* Make sure WPA_Supplicant receives all the event
4452 generated due to DISASSOC call to the fw to keep
4453 the state fw and WPA_Supplicant state consistent
4454 */
4455 brcmf_delay(500);
4456 }
4457
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004458 brcmf_abort_scanning(cfg);
Arend van Sprielc1179032012-10-22 13:55:33 -07004459 clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004460
Arend van Spriel5b435de2011-10-05 13:19:03 +02004461 return 0;
4462}
4463
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004464s32 brcmf_cfg80211_up(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004465{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004466 struct brcmf_if *ifp = netdev_priv(ndev);
4467 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004468 s32 err = 0;
4469
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004470 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004471 err = __brcmf_cfg80211_up(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004472 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004473
4474 return err;
4475}
4476
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004477s32 brcmf_cfg80211_down(struct net_device *ndev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004478{
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004479 struct brcmf_if *ifp = netdev_priv(ndev);
4480 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
Arend van Spriel5b435de2011-10-05 13:19:03 +02004481 s32 err = 0;
4482
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004483 mutex_lock(&cfg->usr_sync);
Arend van Sprielbdf5ff52012-11-14 18:46:09 -08004484 err = __brcmf_cfg80211_down(ifp);
Arend van Spriel27a68fe2012-09-27 14:17:55 +02004485 mutex_unlock(&cfg->usr_sync);
Arend van Spriel5b435de2011-10-05 13:19:03 +02004486
4487 return err;
4488}
4489