blob: c6a10caec79fb94f6d0b9630f29424ea66445828 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
Joe Perches02f77192012-01-15 00:38:44 -080019#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
Arend van Spriel5b435de2011-10-05 13:19:03 +020021#include <linux/kernel.h>
22#include <linux/if_arp.h>
23#include <linux/sched.h>
24#include <linux/kthread.h>
25#include <linux/netdevice.h>
26#include <linux/bitops.h>
27#include <linux/etherdevice.h>
28#include <linux/ieee80211.h>
29#include <linux/uaccess.h>
30#include <net/cfg80211.h>
31
32#include <brcmu_utils.h>
33#include <defs.h>
34#include <brcmu_wifi.h>
35#include "dhd.h"
36#include "wl_cfg80211.h"
37
38#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
39 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
40
41static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
42
43static u32 brcmf_dbg_level = WL_DBG_ERR;
44
45static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data)
46{
47 dev->driver_data = data;
48}
49
50static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev)
51{
52 void *data = NULL;
53
54 if (dev)
55 data = dev->driver_data;
56 return data;
57}
58
59static
60struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev)
61{
62 struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev);
63 return ci->cfg_priv;
64}
65
66static bool check_sys_up(struct wiphy *wiphy)
67{
68 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
69 if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
70 WL_INFO("device is not ready : status (%d)\n",
71 (int)cfg_priv->status);
72 return false;
73 }
74 return true;
75}
76
77#define CHAN2G(_channel, _freq, _flags) { \
78 .band = IEEE80211_BAND_2GHZ, \
79 .center_freq = (_freq), \
80 .hw_value = (_channel), \
81 .flags = (_flags), \
82 .max_antenna_gain = 0, \
83 .max_power = 30, \
84}
85
86#define CHAN5G(_channel, _flags) { \
87 .band = IEEE80211_BAND_5GHZ, \
88 .center_freq = 5000 + (5 * (_channel)), \
89 .hw_value = (_channel), \
90 .flags = (_flags), \
91 .max_antenna_gain = 0, \
92 .max_power = 30, \
93}
94
95#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
96#define RATETAB_ENT(_rateid, _flags) \
97 { \
98 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
99 .hw_value = (_rateid), \
100 .flags = (_flags), \
101 }
102
103static struct ieee80211_rate __wl_rates[] = {
104 RATETAB_ENT(BRCM_RATE_1M, 0),
105 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
106 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
107 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
108 RATETAB_ENT(BRCM_RATE_6M, 0),
109 RATETAB_ENT(BRCM_RATE_9M, 0),
110 RATETAB_ENT(BRCM_RATE_12M, 0),
111 RATETAB_ENT(BRCM_RATE_18M, 0),
112 RATETAB_ENT(BRCM_RATE_24M, 0),
113 RATETAB_ENT(BRCM_RATE_36M, 0),
114 RATETAB_ENT(BRCM_RATE_48M, 0),
115 RATETAB_ENT(BRCM_RATE_54M, 0),
116};
117
118#define wl_a_rates (__wl_rates + 4)
119#define wl_a_rates_size 8
120#define wl_g_rates (__wl_rates + 0)
121#define wl_g_rates_size 12
122
123static struct ieee80211_channel __wl_2ghz_channels[] = {
124 CHAN2G(1, 2412, 0),
125 CHAN2G(2, 2417, 0),
126 CHAN2G(3, 2422, 0),
127 CHAN2G(4, 2427, 0),
128 CHAN2G(5, 2432, 0),
129 CHAN2G(6, 2437, 0),
130 CHAN2G(7, 2442, 0),
131 CHAN2G(8, 2447, 0),
132 CHAN2G(9, 2452, 0),
133 CHAN2G(10, 2457, 0),
134 CHAN2G(11, 2462, 0),
135 CHAN2G(12, 2467, 0),
136 CHAN2G(13, 2472, 0),
137 CHAN2G(14, 2484, 0),
138};
139
140static struct ieee80211_channel __wl_5ghz_a_channels[] = {
141 CHAN5G(34, 0), CHAN5G(36, 0),
142 CHAN5G(38, 0), CHAN5G(40, 0),
143 CHAN5G(42, 0), CHAN5G(44, 0),
144 CHAN5G(46, 0), CHAN5G(48, 0),
145 CHAN5G(52, 0), CHAN5G(56, 0),
146 CHAN5G(60, 0), CHAN5G(64, 0),
147 CHAN5G(100, 0), CHAN5G(104, 0),
148 CHAN5G(108, 0), CHAN5G(112, 0),
149 CHAN5G(116, 0), CHAN5G(120, 0),
150 CHAN5G(124, 0), CHAN5G(128, 0),
151 CHAN5G(132, 0), CHAN5G(136, 0),
152 CHAN5G(140, 0), CHAN5G(149, 0),
153 CHAN5G(153, 0), CHAN5G(157, 0),
154 CHAN5G(161, 0), CHAN5G(165, 0),
155 CHAN5G(184, 0), CHAN5G(188, 0),
156 CHAN5G(192, 0), CHAN5G(196, 0),
157 CHAN5G(200, 0), CHAN5G(204, 0),
158 CHAN5G(208, 0), CHAN5G(212, 0),
159 CHAN5G(216, 0),
160};
161
162static struct ieee80211_channel __wl_5ghz_n_channels[] = {
163 CHAN5G(32, 0), CHAN5G(34, 0),
164 CHAN5G(36, 0), CHAN5G(38, 0),
165 CHAN5G(40, 0), CHAN5G(42, 0),
166 CHAN5G(44, 0), CHAN5G(46, 0),
167 CHAN5G(48, 0), CHAN5G(50, 0),
168 CHAN5G(52, 0), CHAN5G(54, 0),
169 CHAN5G(56, 0), CHAN5G(58, 0),
170 CHAN5G(60, 0), CHAN5G(62, 0),
171 CHAN5G(64, 0), CHAN5G(66, 0),
172 CHAN5G(68, 0), CHAN5G(70, 0),
173 CHAN5G(72, 0), CHAN5G(74, 0),
174 CHAN5G(76, 0), CHAN5G(78, 0),
175 CHAN5G(80, 0), CHAN5G(82, 0),
176 CHAN5G(84, 0), CHAN5G(86, 0),
177 CHAN5G(88, 0), CHAN5G(90, 0),
178 CHAN5G(92, 0), CHAN5G(94, 0),
179 CHAN5G(96, 0), CHAN5G(98, 0),
180 CHAN5G(100, 0), CHAN5G(102, 0),
181 CHAN5G(104, 0), CHAN5G(106, 0),
182 CHAN5G(108, 0), CHAN5G(110, 0),
183 CHAN5G(112, 0), CHAN5G(114, 0),
184 CHAN5G(116, 0), CHAN5G(118, 0),
185 CHAN5G(120, 0), CHAN5G(122, 0),
186 CHAN5G(124, 0), CHAN5G(126, 0),
187 CHAN5G(128, 0), CHAN5G(130, 0),
188 CHAN5G(132, 0), CHAN5G(134, 0),
189 CHAN5G(136, 0), CHAN5G(138, 0),
190 CHAN5G(140, 0), CHAN5G(142, 0),
191 CHAN5G(144, 0), CHAN5G(145, 0),
192 CHAN5G(146, 0), CHAN5G(147, 0),
193 CHAN5G(148, 0), CHAN5G(149, 0),
194 CHAN5G(150, 0), CHAN5G(151, 0),
195 CHAN5G(152, 0), CHAN5G(153, 0),
196 CHAN5G(154, 0), CHAN5G(155, 0),
197 CHAN5G(156, 0), CHAN5G(157, 0),
198 CHAN5G(158, 0), CHAN5G(159, 0),
199 CHAN5G(160, 0), CHAN5G(161, 0),
200 CHAN5G(162, 0), CHAN5G(163, 0),
201 CHAN5G(164, 0), CHAN5G(165, 0),
202 CHAN5G(166, 0), CHAN5G(168, 0),
203 CHAN5G(170, 0), CHAN5G(172, 0),
204 CHAN5G(174, 0), CHAN5G(176, 0),
205 CHAN5G(178, 0), CHAN5G(180, 0),
206 CHAN5G(182, 0), CHAN5G(184, 0),
207 CHAN5G(186, 0), CHAN5G(188, 0),
208 CHAN5G(190, 0), CHAN5G(192, 0),
209 CHAN5G(194, 0), CHAN5G(196, 0),
210 CHAN5G(198, 0), CHAN5G(200, 0),
211 CHAN5G(202, 0), CHAN5G(204, 0),
212 CHAN5G(206, 0), CHAN5G(208, 0),
213 CHAN5G(210, 0), CHAN5G(212, 0),
214 CHAN5G(214, 0), CHAN5G(216, 0),
215 CHAN5G(218, 0), CHAN5G(220, 0),
216 CHAN5G(222, 0), CHAN5G(224, 0),
217 CHAN5G(226, 0), CHAN5G(228, 0),
218};
219
220static struct ieee80211_supported_band __wl_band_2ghz = {
221 .band = IEEE80211_BAND_2GHZ,
222 .channels = __wl_2ghz_channels,
223 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
224 .bitrates = wl_g_rates,
225 .n_bitrates = wl_g_rates_size,
226};
227
228static struct ieee80211_supported_band __wl_band_5ghz_a = {
229 .band = IEEE80211_BAND_5GHZ,
230 .channels = __wl_5ghz_a_channels,
231 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
232 .bitrates = wl_a_rates,
233 .n_bitrates = wl_a_rates_size,
234};
235
236static struct ieee80211_supported_band __wl_band_5ghz_n = {
237 .band = IEEE80211_BAND_5GHZ,
238 .channels = __wl_5ghz_n_channels,
239 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
240 .bitrates = wl_a_rates,
241 .n_bitrates = wl_a_rates_size,
242};
243
244static const u32 __wl_cipher_suites[] = {
245 WLAN_CIPHER_SUITE_WEP40,
246 WLAN_CIPHER_SUITE_WEP104,
247 WLAN_CIPHER_SUITE_TKIP,
248 WLAN_CIPHER_SUITE_CCMP,
249 WLAN_CIPHER_SUITE_AES_CMAC,
250};
251
Alwin Beukersf8e4b412011-10-12 20:51:28 +0200252/* tag_ID/length/value_buffer tuple */
253struct brcmf_tlv {
254 u8 id;
255 u8 len;
256 u8 data[1];
257};
258
Alwin Beukersef6ac172011-10-12 20:51:26 +0200259/* Quarter dBm units to mW
260 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
261 * Table is offset so the last entry is largest mW value that fits in
262 * a u16.
263 */
264
265#define QDBM_OFFSET 153 /* Offset for first entry */
266#define QDBM_TABLE_LEN 40 /* Table size */
267
268/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
269 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
270 */
271#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
272
273/* Largest mW value that will round down to the last table entry,
274 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
275 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
276 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
277 */
278#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
279
280static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
281/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
282/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
283/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
284/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
285/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
286/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
287};
288
289static u16 brcmf_qdbm_to_mw(u8 qdbm)
290{
291 uint factor = 1;
292 int idx = qdbm - QDBM_OFFSET;
293
294 if (idx >= QDBM_TABLE_LEN)
295 /* clamp to max u16 mW value */
296 return 0xFFFF;
297
298 /* scale the qdBm index up to the range of the table 0-40
299 * where an offset of 40 qdBm equals a factor of 10 mW.
300 */
301 while (idx < 0) {
302 idx += 40;
303 factor *= 10;
304 }
305
306 /* return the mW value scaled down to the correct factor of 10,
307 * adding in factor/2 to get proper rounding.
308 */
309 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
310}
311
312static u8 brcmf_mw_to_qdbm(u16 mw)
313{
314 u8 qdbm;
315 int offset;
316 uint mw_uint = mw;
317 uint boundary;
318
319 /* handle boundary case */
320 if (mw_uint <= 1)
321 return 0;
322
323 offset = QDBM_OFFSET;
324
325 /* move mw into the range of the table */
326 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
327 mw_uint *= 10;
328 offset -= 40;
329 }
330
331 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
332 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
333 nqdBm_to_mW_map[qdbm]) / 2;
334 if (mw_uint < boundary)
335 break;
336 }
337
338 qdbm += (u8) offset;
339
340 return qdbm;
341}
342
Arend van Spriel5b435de2011-10-05 13:19:03 +0200343/* function for reading/writing a single u32 from/to the dongle */
344static int
345brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par)
346{
347 int err;
348 __le32 par_le = cpu_to_le32(*par);
349
350 err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32));
351 *par = le32_to_cpu(par_le);
352
353 return err;
354}
355
356static void convert_key_from_CPU(struct brcmf_wsec_key *key,
357 struct brcmf_wsec_key_le *key_le)
358{
359 key_le->index = cpu_to_le32(key->index);
360 key_le->len = cpu_to_le32(key->len);
361 key_le->algo = cpu_to_le32(key->algo);
362 key_le->flags = cpu_to_le32(key->flags);
363 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
364 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
365 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
366 memcpy(key_le->data, key->data, sizeof(key->data));
367 memcpy(key_le->ea, key->ea, sizeof(key->ea));
368}
369
370static int send_key_to_dongle(struct net_device *ndev,
371 struct brcmf_wsec_key *key)
372{
373 int err;
374 struct brcmf_wsec_key_le key_le;
375
376 convert_key_from_CPU(key, &key_le);
377 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le));
378 if (err)
379 WL_ERR("WLC_SET_KEY error (%d)\n", err);
380 return err;
381}
382
383static s32
384brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
385 enum nl80211_iftype type, u32 *flags,
386 struct vif_params *params)
387{
388 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
389 struct wireless_dev *wdev;
390 s32 infra = 0;
391 s32 err = 0;
392
393 WL_TRACE("Enter\n");
394 if (!check_sys_up(wiphy))
395 return -EIO;
396
397 switch (type) {
398 case NL80211_IFTYPE_MONITOR:
399 case NL80211_IFTYPE_WDS:
400 WL_ERR("type (%d) : currently we do not support this type\n",
401 type);
402 return -EOPNOTSUPP;
403 case NL80211_IFTYPE_ADHOC:
404 cfg_priv->conf->mode = WL_MODE_IBSS;
405 infra = 0;
406 break;
407 case NL80211_IFTYPE_STATION:
408 cfg_priv->conf->mode = WL_MODE_BSS;
409 infra = 1;
410 break;
411 default:
412 err = -EINVAL;
413 goto done;
414 }
415
416 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
417 if (err) {
418 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
419 err = -EAGAIN;
420 } else {
421 wdev = ndev->ieee80211_ptr;
422 wdev->iftype = type;
423 }
424
425 WL_INFO("IF Type = %s\n",
426 (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra");
427
428done:
429 WL_TRACE("Exit\n");
430
431 return err;
432}
433
434static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val)
435{
436 s8 buf[BRCMF_DCMD_SMLEN];
437 u32 len;
438 s32 err = 0;
439 __le32 val_le;
440
441 val_le = cpu_to_le32(val);
Alwin Beukers53a22772011-10-12 20:51:30 +0200442 len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200443 sizeof(buf));
444 BUG_ON(!len);
445
446 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
447 if (err)
448 WL_ERR("error (%d)\n", err);
449
450 return err;
451}
452
453static s32
454brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval)
455{
456 union {
457 s8 buf[BRCMF_DCMD_SMLEN];
458 __le32 val;
459 } var;
460 u32 len;
461 u32 data_null;
462 s32 err = 0;
463
464 len =
Alwin Beukers53a22772011-10-12 20:51:30 +0200465 brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
Arend van Spriel5b435de2011-10-05 13:19:03 +0200466 sizeof(var.buf));
467 BUG_ON(!len);
468 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len);
469 if (err)
470 WL_ERR("error (%d)\n", err);
471
472 *retval = le32_to_cpu(var.val);
473
474 return err;
475}
476
477static void brcmf_set_mpc(struct net_device *ndev, int mpc)
478{
479 s32 err = 0;
480 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
481
482 if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
483 err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
484 if (err) {
485 WL_ERR("fail to set mpc\n");
486 return;
487 }
488 WL_INFO("MPC : %d\n", mpc);
489 }
490}
491
492static void wl_iscan_prep(struct brcmf_scan_params_le *params_le,
493 struct brcmf_ssid *ssid)
494{
495 memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
496 params_le->bss_type = DOT11_BSSTYPE_ANY;
497 params_le->scan_type = 0;
498 params_le->channel_num = 0;
499 params_le->nprobes = cpu_to_le32(-1);
500 params_le->active_time = cpu_to_le32(-1);
501 params_le->passive_time = cpu_to_le32(-1);
502 params_le->home_time = cpu_to_le32(-1);
503 if (ssid && ssid->SSID_len)
504 memcpy(&params_le->ssid_le, ssid, sizeof(struct brcmf_ssid));
505}
506
507static s32
508brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param,
509 s32 paramlen, void *bufptr, s32 buflen)
510{
511 s32 iolen;
512
Alwin Beukers53a22772011-10-12 20:51:30 +0200513 iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200514 BUG_ON(!iolen);
515
516 return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen);
517}
518
519static s32
520brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param,
521 s32 paramlen, void *bufptr, s32 buflen)
522{
523 s32 iolen;
524
Alwin Beukers53a22772011-10-12 20:51:30 +0200525 iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200526 BUG_ON(!iolen);
527
528 return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen);
529}
530
531static s32
532brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
533 struct brcmf_ssid *ssid, u16 action)
534{
535 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
536 offsetof(struct brcmf_iscan_params_le, params_le);
537 struct brcmf_iscan_params_le *params;
538 s32 err = 0;
539
540 if (ssid && ssid->SSID_len)
541 params_size += sizeof(struct brcmf_ssid);
542 params = kzalloc(params_size, GFP_KERNEL);
543 if (!params)
544 return -ENOMEM;
545 BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
546
547 wl_iscan_prep(&params->params_le, ssid);
548
549 params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
550 params->action = cpu_to_le16(action);
551 params->scan_duration = cpu_to_le16(0);
552
553 err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size,
554 iscan->dcmd_buf, BRCMF_DCMD_SMLEN);
555 if (err) {
556 if (err == -EBUSY)
557 WL_INFO("system busy : iscan canceled\n");
558 else
559 WL_ERR("error (%d)\n", err);
560 }
561
562 kfree(params);
563 return err;
564}
565
566static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv)
567{
568 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
569 struct net_device *ndev = cfg_to_ndev(cfg_priv);
570 struct brcmf_ssid ssid;
Arend van Spriel66831072011-10-12 20:51:19 +0200571 __le32 passive_scan;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200572 s32 err = 0;
573
574 /* Broadcast scan by default */
575 memset(&ssid, 0, sizeof(ssid));
576
577 iscan->state = WL_ISCAN_STATE_SCANING;
578
Arend van Spriel66831072011-10-12 20:51:19 +0200579 passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200580 err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN,
581 &passive_scan, sizeof(passive_scan));
582 if (err) {
583 WL_ERR("error (%d)\n", err);
584 return err;
585 }
586 brcmf_set_mpc(ndev, 0);
587 cfg_priv->iscan_kickstart = true;
588 err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
589 if (err) {
590 brcmf_set_mpc(ndev, 1);
591 cfg_priv->iscan_kickstart = false;
592 return err;
593 }
594 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
595 iscan->timer_on = 1;
596 return err;
597}
598
599static s32
600__brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
601 struct cfg80211_scan_request *request,
602 struct cfg80211_ssid *this_ssid)
603{
604 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
605 struct cfg80211_ssid *ssids;
606 struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int;
Arend van Spriel66831072011-10-12 20:51:19 +0200607 __le32 passive_scan;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200608 bool iscan_req;
609 bool spec_scan;
610 s32 err = 0;
611 u32 SSID_len;
612
613 if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
614 WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status);
615 return -EAGAIN;
616 }
617 if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) {
618 WL_ERR("Scanning being aborted : status (%lu)\n",
619 cfg_priv->status);
620 return -EAGAIN;
621 }
622 if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
623 WL_ERR("Connecting : status (%lu)\n",
624 cfg_priv->status);
625 return -EAGAIN;
626 }
627
628 iscan_req = false;
629 spec_scan = false;
630 if (request) {
631 /* scan bss */
632 ssids = request->ssids;
633 if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len))
634 iscan_req = true;
635 } else {
636 /* scan in ibss */
637 /* we don't do iscan in ibss */
638 ssids = this_ssid;
639 }
640
641 cfg_priv->scan_request = request;
642 set_bit(WL_STATUS_SCANNING, &cfg_priv->status);
643 if (iscan_req) {
644 err = brcmf_do_iscan(cfg_priv);
645 if (!err)
646 return err;
647 else
648 goto scan_out;
649 } else {
650 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
651 ssids->ssid, ssids->ssid_len);
652 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
653 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
654 sr->ssid_le.SSID_len = cpu_to_le32(0);
655 if (SSID_len) {
656 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
657 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
658 spec_scan = true;
659 } else {
660 WL_SCAN("Broadcast scan\n");
661 }
662
Arend van Spriel66831072011-10-12 20:51:19 +0200663 passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200664 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
665 &passive_scan, sizeof(passive_scan));
666 if (err) {
667 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
668 goto scan_out;
669 }
670 brcmf_set_mpc(ndev, 0);
671 err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
672 sizeof(sr->ssid_le));
673 if (err) {
674 if (err == -EBUSY)
675 WL_INFO("system busy : scan for \"%s\" "
676 "canceled\n", sr->ssid_le.SSID);
677 else
678 WL_ERR("WLC_SCAN error (%d)\n", err);
679
680 brcmf_set_mpc(ndev, 1);
681 goto scan_out;
682 }
683 }
684
685 return 0;
686
687scan_out:
688 clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
689 cfg_priv->scan_request = NULL;
690 return err;
691}
692
693static s32
Johannes Bergfd014282012-06-18 19:17:03 +0200694brcmf_cfg80211_scan(struct wiphy *wiphy,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200695 struct cfg80211_scan_request *request)
696{
Johannes Bergfd014282012-06-18 19:17:03 +0200697 struct net_device *ndev = request->wdev->netdev;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200698 s32 err = 0;
699
700 WL_TRACE("Enter\n");
701
702 if (!check_sys_up(wiphy))
703 return -EIO;
704
705 err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL);
706 if (err)
707 WL_ERR("scan error (%d)\n", err);
708
709 WL_TRACE("Exit\n");
710 return err;
711}
712
713static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
714{
715 s32 err = 0;
716
717 err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold);
718 if (err)
719 WL_ERR("Error (%d)\n", err);
720
721 return err;
722}
723
724static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
725{
726 s32 err = 0;
727
728 err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold);
729 if (err)
730 WL_ERR("Error (%d)\n", err);
731
732 return err;
733}
734
735static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
736{
737 s32 err = 0;
738 u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
739
740 err = brcmf_exec_dcmd_u32(ndev, cmd, &retry);
741 if (err) {
742 WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
743 return err;
744 }
745 return err;
746}
747
748static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
749{
750 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
751 struct net_device *ndev = cfg_to_ndev(cfg_priv);
752 s32 err = 0;
753
754 WL_TRACE("Enter\n");
755 if (!check_sys_up(wiphy))
756 return -EIO;
757
758 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
759 (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) {
760 cfg_priv->conf->rts_threshold = wiphy->rts_threshold;
761 err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold);
762 if (!err)
763 goto done;
764 }
765 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
766 (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) {
767 cfg_priv->conf->frag_threshold = wiphy->frag_threshold;
768 err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold);
769 if (!err)
770 goto done;
771 }
772 if (changed & WIPHY_PARAM_RETRY_LONG
773 && (cfg_priv->conf->retry_long != wiphy->retry_long)) {
774 cfg_priv->conf->retry_long = wiphy->retry_long;
775 err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true);
776 if (!err)
777 goto done;
778 }
779 if (changed & WIPHY_PARAM_RETRY_SHORT
780 && (cfg_priv->conf->retry_short != wiphy->retry_short)) {
781 cfg_priv->conf->retry_short = wiphy->retry_short;
782 err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false);
783 if (!err)
784 goto done;
785 }
786
787done:
788 WL_TRACE("Exit\n");
789 return err;
790}
791
792static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item)
793{
794 switch (item) {
795 case WL_PROF_SEC:
796 return &cfg_priv->profile->sec;
797 case WL_PROF_BSSID:
798 return &cfg_priv->profile->bssid;
799 case WL_PROF_SSID:
800 return &cfg_priv->profile->ssid;
801 }
802 WL_ERR("invalid item (%d)\n", item);
803 return NULL;
804}
805
806static s32
807brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
808 const struct brcmf_event_msg *e, void *data, s32 item)
809{
810 s32 err = 0;
811 struct brcmf_ssid *ssid;
812
813 switch (item) {
814 case WL_PROF_SSID:
815 ssid = (struct brcmf_ssid *) data;
816 memset(cfg_priv->profile->ssid.SSID, 0,
817 sizeof(cfg_priv->profile->ssid.SSID));
818 memcpy(cfg_priv->profile->ssid.SSID,
819 ssid->SSID, ssid->SSID_len);
820 cfg_priv->profile->ssid.SSID_len = ssid->SSID_len;
821 break;
822 case WL_PROF_BSSID:
823 if (data)
824 memcpy(cfg_priv->profile->bssid, data, ETH_ALEN);
825 else
826 memset(cfg_priv->profile->bssid, 0, ETH_ALEN);
827 break;
828 case WL_PROF_SEC:
829 memcpy(&cfg_priv->profile->sec, data,
830 sizeof(cfg_priv->profile->sec));
831 break;
832 case WL_PROF_BEACONINT:
833 cfg_priv->profile->beacon_interval = *(u16 *)data;
834 break;
835 case WL_PROF_DTIMPERIOD:
836 cfg_priv->profile->dtim_period = *(u8 *)data;
837 break;
838 default:
839 WL_ERR("unsupported item (%d)\n", item);
840 err = -EOPNOTSUPP;
841 break;
842 }
843
844 return err;
845}
846
847static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
848{
849 memset(prof, 0, sizeof(*prof));
850}
851
852static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
853 size_t *join_params_size)
854{
855 u16 chanspec = 0;
856
857 if (ch != 0) {
858 if (ch <= CH_MAX_2G_CHANNEL)
859 chanspec |= WL_CHANSPEC_BAND_2G;
860 else
861 chanspec |= WL_CHANSPEC_BAND_5G;
862
863 chanspec |= WL_CHANSPEC_BW_20;
864 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
865
866 *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
867 sizeof(u16);
868
869 chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
870 join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
871 join_params->params_le.chanspec_num = cpu_to_le32(1);
872
873 WL_CONN("join_params->params.chanspec_list[0]= %#X,"
874 "channel %d, chanspec %#X\n",
875 chanspec, ch, chanspec);
876 }
877}
878
879static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv)
880{
881 struct net_device *ndev = NULL;
882 s32 err = 0;
883
884 WL_TRACE("Enter\n");
885
886 if (cfg_priv->link_up) {
887 ndev = cfg_to_ndev(cfg_priv);
888 WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
889 err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0);
890 if (err)
891 WL_ERR("WLC_DISASSOC failed (%d)\n", err);
892 cfg_priv->link_up = false;
893 }
894 WL_TRACE("Exit\n");
895}
896
897static s32
898brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
899 struct cfg80211_ibss_params *params)
900{
901 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
902 struct brcmf_join_params join_params;
903 size_t join_params_size = 0;
904 s32 err = 0;
905 s32 wsec = 0;
906 s32 bcnprd;
907 struct brcmf_ssid ssid;
908
909 WL_TRACE("Enter\n");
910 if (!check_sys_up(wiphy))
911 return -EIO;
912
913 if (params->ssid)
914 WL_CONN("SSID: %s\n", params->ssid);
915 else {
916 WL_CONN("SSID: NULL, Not supported\n");
917 return -EOPNOTSUPP;
918 }
919
920 set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
921
922 if (params->bssid)
923 WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n",
924 params->bssid[0], params->bssid[1], params->bssid[2],
925 params->bssid[3], params->bssid[4], params->bssid[5]);
926 else
927 WL_CONN("No BSSID specified\n");
928
929 if (params->channel)
930 WL_CONN("channel: %d\n", params->channel->center_freq);
931 else
932 WL_CONN("no channel specified\n");
933
934 if (params->channel_fixed)
935 WL_CONN("fixed channel required\n");
936 else
937 WL_CONN("no fixed channel required\n");
938
939 if (params->ie && params->ie_len)
940 WL_CONN("ie len: %d\n", params->ie_len);
941 else
942 WL_CONN("no ie specified\n");
943
944 if (params->beacon_interval)
945 WL_CONN("beacon interval: %d\n", params->beacon_interval);
946 else
947 WL_CONN("no beacon interval specified\n");
948
949 if (params->basic_rates)
950 WL_CONN("basic rates: %08X\n", params->basic_rates);
951 else
952 WL_CONN("no basic rates specified\n");
953
954 if (params->privacy)
955 WL_CONN("privacy required\n");
956 else
957 WL_CONN("no privacy required\n");
958
959 /* Configure Privacy for starter */
960 if (params->privacy)
961 wsec |= WEP_ENABLED;
962
963 err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
964 if (err) {
965 WL_ERR("wsec failed (%d)\n", err);
966 goto done;
967 }
968
969 /* Configure Beacon Interval for starter */
970 if (params->beacon_interval)
971 bcnprd = params->beacon_interval;
972 else
973 bcnprd = 100;
974
975 err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd);
976 if (err) {
977 WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
978 goto done;
979 }
980
981 /* Configure required join parameter */
982 memset(&join_params, 0, sizeof(struct brcmf_join_params));
983
984 /* SSID */
985 ssid.SSID_len = min_t(u32, params->ssid_len, 32);
986 memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
987 memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len);
988 join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
989 join_params_size = sizeof(join_params.ssid_le);
990 brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
991
992 /* BSSID */
993 if (params->bssid) {
994 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
995 join_params_size = sizeof(join_params.ssid_le) +
996 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
997 } else {
998 memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
999 }
1000
1001 brcmf_update_prof(cfg_priv, NULL,
1002 &join_params.params_le.bssid, WL_PROF_BSSID);
1003
1004 /* Channel */
1005 if (params->channel) {
1006 u32 target_channel;
1007
1008 cfg_priv->channel =
1009 ieee80211_frequency_to_channel(
1010 params->channel->center_freq);
1011 if (params->channel_fixed) {
1012 /* adding chanspec */
1013 brcmf_ch_to_chanspec(cfg_priv->channel,
1014 &join_params, &join_params_size);
1015 }
1016
1017 /* set channel for starter */
1018 target_channel = cfg_priv->channel;
1019 err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL,
1020 &target_channel);
1021 if (err) {
1022 WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
1023 goto done;
1024 }
1025 } else
1026 cfg_priv->channel = 0;
1027
1028 cfg_priv->ibss_starter = false;
1029
1030
1031 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
1032 &join_params, join_params_size);
1033 if (err) {
1034 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1035 goto done;
1036 }
1037
1038done:
1039 if (err)
1040 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
1041 WL_TRACE("Exit\n");
1042 return err;
1043}
1044
1045static s32
1046brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1047{
1048 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1049 s32 err = 0;
1050
1051 WL_TRACE("Enter\n");
1052 if (!check_sys_up(wiphy))
1053 return -EIO;
1054
1055 brcmf_link_down(cfg_priv);
1056
1057 WL_TRACE("Exit\n");
1058
1059 return err;
1060}
1061
1062static s32 brcmf_set_wpa_version(struct net_device *ndev,
1063 struct cfg80211_connect_params *sme)
1064{
1065 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1066 struct brcmf_cfg80211_security *sec;
1067 s32 val = 0;
1068 s32 err = 0;
1069
1070 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1071 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1072 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1073 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1074 else
1075 val = WPA_AUTH_DISABLED;
1076 WL_CONN("setting wpa_auth to 0x%0x\n", val);
1077 err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
1078 if (err) {
1079 WL_ERR("set wpa_auth failed (%d)\n", err);
1080 return err;
1081 }
1082 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1083 sec->wpa_versions = sme->crypto.wpa_versions;
1084 return err;
1085}
1086
1087static s32 brcmf_set_auth_type(struct net_device *ndev,
1088 struct cfg80211_connect_params *sme)
1089{
1090 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1091 struct brcmf_cfg80211_security *sec;
1092 s32 val = 0;
1093 s32 err = 0;
1094
1095 switch (sme->auth_type) {
1096 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1097 val = 0;
1098 WL_CONN("open system\n");
1099 break;
1100 case NL80211_AUTHTYPE_SHARED_KEY:
1101 val = 1;
1102 WL_CONN("shared key\n");
1103 break;
1104 case NL80211_AUTHTYPE_AUTOMATIC:
1105 val = 2;
1106 WL_CONN("automatic\n");
1107 break;
1108 case NL80211_AUTHTYPE_NETWORK_EAP:
1109 WL_CONN("network eap\n");
1110 default:
1111 val = 2;
1112 WL_ERR("invalid auth type (%d)\n", sme->auth_type);
1113 break;
1114 }
1115
1116 err = brcmf_dev_intvar_set(ndev, "auth", val);
1117 if (err) {
1118 WL_ERR("set auth failed (%d)\n", err);
1119 return err;
1120 }
1121 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1122 sec->auth_type = sme->auth_type;
1123 return err;
1124}
1125
1126static s32
1127brcmf_set_set_cipher(struct net_device *ndev,
1128 struct cfg80211_connect_params *sme)
1129{
1130 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1131 struct brcmf_cfg80211_security *sec;
1132 s32 pval = 0;
1133 s32 gval = 0;
1134 s32 err = 0;
1135
1136 if (sme->crypto.n_ciphers_pairwise) {
1137 switch (sme->crypto.ciphers_pairwise[0]) {
1138 case WLAN_CIPHER_SUITE_WEP40:
1139 case WLAN_CIPHER_SUITE_WEP104:
1140 pval = WEP_ENABLED;
1141 break;
1142 case WLAN_CIPHER_SUITE_TKIP:
1143 pval = TKIP_ENABLED;
1144 break;
1145 case WLAN_CIPHER_SUITE_CCMP:
1146 pval = AES_ENABLED;
1147 break;
1148 case WLAN_CIPHER_SUITE_AES_CMAC:
1149 pval = AES_ENABLED;
1150 break;
1151 default:
1152 WL_ERR("invalid cipher pairwise (%d)\n",
1153 sme->crypto.ciphers_pairwise[0]);
1154 return -EINVAL;
1155 }
1156 }
1157 if (sme->crypto.cipher_group) {
1158 switch (sme->crypto.cipher_group) {
1159 case WLAN_CIPHER_SUITE_WEP40:
1160 case WLAN_CIPHER_SUITE_WEP104:
1161 gval = WEP_ENABLED;
1162 break;
1163 case WLAN_CIPHER_SUITE_TKIP:
1164 gval = TKIP_ENABLED;
1165 break;
1166 case WLAN_CIPHER_SUITE_CCMP:
1167 gval = AES_ENABLED;
1168 break;
1169 case WLAN_CIPHER_SUITE_AES_CMAC:
1170 gval = AES_ENABLED;
1171 break;
1172 default:
1173 WL_ERR("invalid cipher group (%d)\n",
1174 sme->crypto.cipher_group);
1175 return -EINVAL;
1176 }
1177 }
1178
1179 WL_CONN("pval (%d) gval (%d)\n", pval, gval);
1180 err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval);
1181 if (err) {
1182 WL_ERR("error (%d)\n", err);
1183 return err;
1184 }
1185
1186 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1187 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1188 sec->cipher_group = sme->crypto.cipher_group;
1189
1190 return err;
1191}
1192
1193static s32
1194brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1195{
1196 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1197 struct brcmf_cfg80211_security *sec;
1198 s32 val = 0;
1199 s32 err = 0;
1200
1201 if (sme->crypto.n_akm_suites) {
1202 err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val);
1203 if (err) {
1204 WL_ERR("could not get wpa_auth (%d)\n", err);
1205 return err;
1206 }
1207 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1208 switch (sme->crypto.akm_suites[0]) {
1209 case WLAN_AKM_SUITE_8021X:
1210 val = WPA_AUTH_UNSPECIFIED;
1211 break;
1212 case WLAN_AKM_SUITE_PSK:
1213 val = WPA_AUTH_PSK;
1214 break;
1215 default:
1216 WL_ERR("invalid cipher group (%d)\n",
1217 sme->crypto.cipher_group);
1218 return -EINVAL;
1219 }
1220 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1221 switch (sme->crypto.akm_suites[0]) {
1222 case WLAN_AKM_SUITE_8021X:
1223 val = WPA2_AUTH_UNSPECIFIED;
1224 break;
1225 case WLAN_AKM_SUITE_PSK:
1226 val = WPA2_AUTH_PSK;
1227 break;
1228 default:
1229 WL_ERR("invalid cipher group (%d)\n",
1230 sme->crypto.cipher_group);
1231 return -EINVAL;
1232 }
1233 }
1234
1235 WL_CONN("setting wpa_auth to %d\n", val);
1236 err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
1237 if (err) {
1238 WL_ERR("could not set wpa_auth (%d)\n", err);
1239 return err;
1240 }
1241 }
1242 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1243 sec->wpa_auth = sme->crypto.akm_suites[0];
1244
1245 return err;
1246}
1247
1248static s32
Roland Vossena718e2f2011-10-12 20:51:24 +02001249brcmf_set_wep_sharedkey(struct net_device *ndev,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001250 struct cfg80211_connect_params *sme)
1251{
1252 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1253 struct brcmf_cfg80211_security *sec;
1254 struct brcmf_wsec_key key;
1255 s32 val;
1256 s32 err = 0;
1257
1258 WL_CONN("key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001259
Roland Vossena718e2f2011-10-12 20:51:24 +02001260 if (sme->key_len == 0)
1261 return 0;
1262
1263 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1264 WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n",
1265 sec->wpa_versions, sec->cipher_pairwise);
1266
1267 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1268 return 0;
1269
1270 if (sec->cipher_pairwise &
1271 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) {
1272 memset(&key, 0, sizeof(key));
1273 key.len = (u32) sme->key_len;
1274 key.index = (u32) sme->key_idx;
1275 if (key.len > sizeof(key.data)) {
1276 WL_ERR("Too long key length (%u)\n", key.len);
1277 return -EINVAL;
1278 }
1279 memcpy(key.data, sme->key, key.len);
1280 key.flags = BRCMF_PRIMARY_KEY;
1281 switch (sec->cipher_pairwise) {
1282 case WLAN_CIPHER_SUITE_WEP40:
1283 key.algo = CRYPTO_ALGO_WEP1;
1284 break;
1285 case WLAN_CIPHER_SUITE_WEP104:
1286 key.algo = CRYPTO_ALGO_WEP128;
1287 break;
1288 default:
1289 WL_ERR("Invalid algorithm (%d)\n",
1290 sme->crypto.ciphers_pairwise[0]);
1291 return -EINVAL;
1292 }
1293 /* Set the new key/index */
1294 WL_CONN("key length (%d) key index (%d) algo (%d)\n",
1295 key.len, key.index, key.algo);
1296 WL_CONN("key \"%s\"\n", key.data);
1297 err = send_key_to_dongle(ndev, &key);
1298 if (err)
1299 return err;
1300
1301 if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
1302 WL_CONN("set auth_type to shared key\n");
1303 val = 1; /* shared key */
1304 err = brcmf_dev_intvar_set(ndev, "auth", val);
1305 if (err) {
1306 WL_ERR("set auth failed (%d)\n", err);
1307 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001308 }
1309 }
1310 }
1311 return err;
1312}
1313
1314static s32
1315brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1316 struct cfg80211_connect_params *sme)
1317{
1318 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1319 struct ieee80211_channel *chan = sme->channel;
1320 struct brcmf_join_params join_params;
1321 size_t join_params_size;
1322 struct brcmf_ssid ssid;
1323
1324 s32 err = 0;
1325
1326 WL_TRACE("Enter\n");
1327 if (!check_sys_up(wiphy))
1328 return -EIO;
1329
1330 if (!sme->ssid) {
1331 WL_ERR("Invalid ssid\n");
1332 return -EOPNOTSUPP;
1333 }
1334
1335 set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
1336
1337 if (chan) {
1338 cfg_priv->channel =
1339 ieee80211_frequency_to_channel(chan->center_freq);
1340 WL_CONN("channel (%d), center_req (%d)\n",
1341 cfg_priv->channel, chan->center_freq);
1342 } else
1343 cfg_priv->channel = 0;
1344
1345 WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1346
1347 err = brcmf_set_wpa_version(ndev, sme);
1348 if (err) {
1349 WL_ERR("wl_set_wpa_version failed (%d)\n", err);
1350 goto done;
1351 }
1352
1353 err = brcmf_set_auth_type(ndev, sme);
1354 if (err) {
1355 WL_ERR("wl_set_auth_type failed (%d)\n", err);
1356 goto done;
1357 }
1358
1359 err = brcmf_set_set_cipher(ndev, sme);
1360 if (err) {
1361 WL_ERR("wl_set_set_cipher failed (%d)\n", err);
1362 goto done;
1363 }
1364
1365 err = brcmf_set_key_mgmt(ndev, sme);
1366 if (err) {
1367 WL_ERR("wl_set_key_mgmt failed (%d)\n", err);
1368 goto done;
1369 }
1370
Roland Vossena718e2f2011-10-12 20:51:24 +02001371 err = brcmf_set_wep_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001372 if (err) {
Roland Vossena718e2f2011-10-12 20:51:24 +02001373 WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001374 goto done;
1375 }
1376
1377 memset(&join_params, 0, sizeof(join_params));
1378 join_params_size = sizeof(join_params.ssid_le);
1379
Arend van Spriel23159922012-02-09 21:09:00 +01001380 ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), (u32)sme->ssid_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001381 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len);
1382 memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len);
1383 join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
1384 brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
1385
1386 memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
1387
1388 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
1389 WL_CONN("ssid \"%s\", len (%d)\n",
1390 ssid.SSID, ssid.SSID_len);
1391
1392 brcmf_ch_to_chanspec(cfg_priv->channel,
1393 &join_params, &join_params_size);
1394 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
1395 &join_params, join_params_size);
1396 if (err)
1397 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1398
1399done:
1400 if (err)
1401 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
1402 WL_TRACE("Exit\n");
1403 return err;
1404}
1405
1406static s32
1407brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1408 u16 reason_code)
1409{
1410 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1411 struct brcmf_scb_val_le scbval;
1412 s32 err = 0;
1413
1414 WL_TRACE("Enter. Reason code = %d\n", reason_code);
1415 if (!check_sys_up(wiphy))
1416 return -EIO;
1417
1418 clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
1419
1420 memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN);
1421 scbval.val = cpu_to_le32(reason_code);
1422 err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval,
1423 sizeof(struct brcmf_scb_val_le));
1424 if (err)
1425 WL_ERR("error (%d)\n", err);
1426
1427 cfg_priv->link_up = false;
1428
1429 WL_TRACE("Exit\n");
1430 return err;
1431}
1432
1433static s32
1434brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001435 enum nl80211_tx_power_setting type, s32 mbm)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001436{
1437
1438 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1439 struct net_device *ndev = cfg_to_ndev(cfg_priv);
1440 u16 txpwrmw;
1441 s32 err = 0;
1442 s32 disable = 0;
Luis R. Rodriguezd3f31132011-11-28 16:38:48 -05001443 s32 dbm = MBM_TO_DBM(mbm);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001444
1445 WL_TRACE("Enter\n");
1446 if (!check_sys_up(wiphy))
1447 return -EIO;
1448
1449 switch (type) {
1450 case NL80211_TX_POWER_AUTOMATIC:
1451 break;
1452 case NL80211_TX_POWER_LIMITED:
Arend van Spriel5b435de2011-10-05 13:19:03 +02001453 case NL80211_TX_POWER_FIXED:
1454 if (dbm < 0) {
1455 WL_ERR("TX_POWER_FIXED - dbm is negative\n");
1456 err = -EINVAL;
1457 goto done;
1458 }
1459 break;
1460 }
1461 /* Make sure radio is off or on as far as software is concerned */
1462 disable = WL_RADIO_SW_DISABLE << 16;
1463 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable);
1464 if (err)
1465 WL_ERR("WLC_SET_RADIO error (%d)\n", err);
1466
1467 if (dbm > 0xffff)
1468 txpwrmw = 0xffff;
1469 else
1470 txpwrmw = (u16) dbm;
1471 err = brcmf_dev_intvar_set(ndev, "qtxpower",
Alwin Beukersef6ac172011-10-12 20:51:26 +02001472 (s32) (brcmf_mw_to_qdbm(txpwrmw)));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001473 if (err)
1474 WL_ERR("qtxpower error (%d)\n", err);
1475 cfg_priv->conf->tx_power = dbm;
1476
1477done:
1478 WL_TRACE("Exit\n");
1479 return err;
1480}
1481
1482static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
1483{
1484 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1485 struct net_device *ndev = cfg_to_ndev(cfg_priv);
1486 s32 txpwrdbm;
1487 u8 result;
1488 s32 err = 0;
1489
1490 WL_TRACE("Enter\n");
1491 if (!check_sys_up(wiphy))
1492 return -EIO;
1493
1494 err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
1495 if (err) {
1496 WL_ERR("error (%d)\n", err);
1497 goto done;
1498 }
1499
1500 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001501 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001502
1503done:
1504 WL_TRACE("Exit\n");
1505 return err;
1506}
1507
1508static s32
1509brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1510 u8 key_idx, bool unicast, bool multicast)
1511{
1512 u32 index;
1513 u32 wsec;
1514 s32 err = 0;
1515
1516 WL_TRACE("Enter\n");
1517 WL_CONN("key index (%d)\n", key_idx);
1518 if (!check_sys_up(wiphy))
1519 return -EIO;
1520
1521 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
1522 if (err) {
1523 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1524 goto done;
1525 }
1526
1527 if (wsec & WEP_ENABLED) {
1528 /* Just select a new current key */
1529 index = key_idx;
1530 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY,
1531 &index);
1532 if (err)
1533 WL_ERR("error (%d)\n", err);
1534 }
1535done:
1536 WL_TRACE("Exit\n");
1537 return err;
1538}
1539
1540static s32
1541brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1542 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1543{
1544 struct brcmf_wsec_key key;
1545 struct brcmf_wsec_key_le key_le;
1546 s32 err = 0;
1547
1548 memset(&key, 0, sizeof(key));
1549 key.index = (u32) key_idx;
1550 /* Instead of bcast for ea address for default wep keys,
1551 driver needs it to be Null */
1552 if (!is_multicast_ether_addr(mac_addr))
1553 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1554 key.len = (u32) params->key_len;
1555 /* check for key index change */
1556 if (key.len == 0) {
1557 /* key delete */
1558 err = send_key_to_dongle(ndev, &key);
1559 if (err)
1560 return err;
1561 } else {
1562 if (key.len > sizeof(key.data)) {
1563 WL_ERR("Invalid key length (%d)\n", key.len);
1564 return -EINVAL;
1565 }
1566
1567 WL_CONN("Setting the key index %d\n", key.index);
1568 memcpy(key.data, params->key, key.len);
1569
1570 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1571 u8 keybuf[8];
1572 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1573 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1574 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1575 }
1576
1577 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1578 if (params->seq && params->seq_len == 6) {
1579 /* rx iv */
1580 u8 *ivptr;
1581 ivptr = (u8 *) params->seq;
1582 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1583 (ivptr[3] << 8) | ivptr[2];
1584 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1585 key.iv_initialized = true;
1586 }
1587
1588 switch (params->cipher) {
1589 case WLAN_CIPHER_SUITE_WEP40:
1590 key.algo = CRYPTO_ALGO_WEP1;
1591 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1592 break;
1593 case WLAN_CIPHER_SUITE_WEP104:
1594 key.algo = CRYPTO_ALGO_WEP128;
1595 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1596 break;
1597 case WLAN_CIPHER_SUITE_TKIP:
1598 key.algo = CRYPTO_ALGO_TKIP;
1599 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1600 break;
1601 case WLAN_CIPHER_SUITE_AES_CMAC:
1602 key.algo = CRYPTO_ALGO_AES_CCM;
1603 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1604 break;
1605 case WLAN_CIPHER_SUITE_CCMP:
1606 key.algo = CRYPTO_ALGO_AES_CCM;
1607 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
1608 break;
1609 default:
1610 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1611 return -EINVAL;
1612 }
1613 convert_key_from_CPU(&key, &key_le);
1614
1615 brcmf_netdev_wait_pend8021x(ndev);
1616 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le,
1617 sizeof(key_le));
1618 if (err) {
1619 WL_ERR("WLC_SET_KEY error (%d)\n", err);
1620 return err;
1621 }
1622 }
1623 return err;
1624}
1625
1626static s32
1627brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1628 u8 key_idx, bool pairwise, const u8 *mac_addr,
1629 struct key_params *params)
1630{
1631 struct brcmf_wsec_key key;
1632 s32 val;
1633 s32 wsec;
1634 s32 err = 0;
1635 u8 keybuf[8];
1636
1637 WL_TRACE("Enter\n");
1638 WL_CONN("key index (%d)\n", key_idx);
1639 if (!check_sys_up(wiphy))
1640 return -EIO;
1641
1642 if (mac_addr) {
1643 WL_TRACE("Exit");
1644 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1645 }
1646 memset(&key, 0, sizeof(key));
1647
1648 key.len = (u32) params->key_len;
1649 key.index = (u32) key_idx;
1650
1651 if (key.len > sizeof(key.data)) {
1652 WL_ERR("Too long key length (%u)\n", key.len);
1653 err = -EINVAL;
1654 goto done;
1655 }
1656 memcpy(key.data, params->key, key.len);
1657
1658 key.flags = BRCMF_PRIMARY_KEY;
1659 switch (params->cipher) {
1660 case WLAN_CIPHER_SUITE_WEP40:
1661 key.algo = CRYPTO_ALGO_WEP1;
1662 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1663 break;
1664 case WLAN_CIPHER_SUITE_WEP104:
1665 key.algo = CRYPTO_ALGO_WEP128;
1666 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1667 break;
1668 case WLAN_CIPHER_SUITE_TKIP:
1669 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1670 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1671 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1672 key.algo = CRYPTO_ALGO_TKIP;
1673 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1674 break;
1675 case WLAN_CIPHER_SUITE_AES_CMAC:
1676 key.algo = CRYPTO_ALGO_AES_CCM;
1677 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1678 break;
1679 case WLAN_CIPHER_SUITE_CCMP:
1680 key.algo = CRYPTO_ALGO_AES_CCM;
1681 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
1682 break;
1683 default:
1684 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1685 err = -EINVAL;
1686 goto done;
1687 }
1688
1689 err = send_key_to_dongle(ndev, &key); /* Set the new key/index */
1690 if (err)
1691 goto done;
1692
1693 val = WEP_ENABLED;
1694 err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
1695 if (err) {
1696 WL_ERR("get wsec error (%d)\n", err);
1697 goto done;
1698 }
1699 wsec &= ~(WEP_ENABLED);
1700 wsec |= val;
1701 err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
1702 if (err) {
1703 WL_ERR("set wsec error (%d)\n", err);
1704 goto done;
1705 }
1706
1707 val = 1; /* assume shared key. otherwise 0 */
1708 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
1709 if (err)
1710 WL_ERR("WLC_SET_AUTH error (%d)\n", err);
1711done:
1712 WL_TRACE("Exit\n");
1713 return err;
1714}
1715
1716static s32
1717brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1718 u8 key_idx, bool pairwise, const u8 *mac_addr)
1719{
1720 struct brcmf_wsec_key key;
1721 s32 err = 0;
1722 s32 val;
1723 s32 wsec;
1724
1725 WL_TRACE("Enter\n");
1726 if (!check_sys_up(wiphy))
1727 return -EIO;
1728
1729 memset(&key, 0, sizeof(key));
1730
1731 key.index = (u32) key_idx;
1732 key.flags = BRCMF_PRIMARY_KEY;
1733 key.algo = CRYPTO_ALGO_OFF;
1734
1735 WL_CONN("key index (%d)\n", key_idx);
1736
1737 /* Set the new key/index */
1738 err = send_key_to_dongle(ndev, &key);
1739 if (err) {
1740 if (err == -EINVAL) {
1741 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
1742 /* we ignore this key index in this case */
1743 WL_ERR("invalid key index (%d)\n", key_idx);
1744 }
1745 /* Ignore this error, may happen during DISASSOC */
1746 err = -EAGAIN;
1747 goto done;
1748 }
1749
1750 val = 0;
1751 err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
1752 if (err) {
1753 WL_ERR("get wsec error (%d)\n", err);
1754 /* Ignore this error, may happen during DISASSOC */
1755 err = -EAGAIN;
1756 goto done;
1757 }
1758 wsec &= ~(WEP_ENABLED);
1759 wsec |= val;
1760 err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
1761 if (err) {
1762 WL_ERR("set wsec error (%d)\n", err);
1763 /* Ignore this error, may happen during DISASSOC */
1764 err = -EAGAIN;
1765 goto done;
1766 }
1767
1768 val = 0; /* assume open key. otherwise 1 */
1769 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
1770 if (err) {
1771 WL_ERR("WLC_SET_AUTH error (%d)\n", err);
1772 /* Ignore this error, may happen during DISASSOC */
1773 err = -EAGAIN;
1774 }
1775done:
1776 WL_TRACE("Exit\n");
1777 return err;
1778}
1779
1780static s32
1781brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1782 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
1783 void (*callback) (void *cookie, struct key_params * params))
1784{
1785 struct key_params params;
1786 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1787 struct brcmf_cfg80211_security *sec;
1788 s32 wsec;
1789 s32 err = 0;
1790
1791 WL_TRACE("Enter\n");
1792 WL_CONN("key index (%d)\n", key_idx);
1793 if (!check_sys_up(wiphy))
1794 return -EIO;
1795
1796 memset(&params, 0, sizeof(params));
1797
1798 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
1799 if (err) {
1800 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1801 /* Ignore this error, may happen during DISASSOC */
1802 err = -EAGAIN;
1803 goto done;
1804 }
1805 switch (wsec) {
1806 case WEP_ENABLED:
1807 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1808 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1809 params.cipher = WLAN_CIPHER_SUITE_WEP40;
1810 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1811 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1812 params.cipher = WLAN_CIPHER_SUITE_WEP104;
1813 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1814 }
1815 break;
1816 case TKIP_ENABLED:
1817 params.cipher = WLAN_CIPHER_SUITE_TKIP;
1818 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1819 break;
1820 case AES_ENABLED:
1821 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
1822 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1823 break;
1824 default:
1825 WL_ERR("Invalid algo (0x%x)\n", wsec);
1826 err = -EINVAL;
1827 goto done;
1828 }
1829 callback(cookie, &params);
1830
1831done:
1832 WL_TRACE("Exit\n");
1833 return err;
1834}
1835
1836static s32
1837brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
1838 struct net_device *ndev, u8 key_idx)
1839{
1840 WL_INFO("Not supported\n");
1841
1842 return -EOPNOTSUPP;
1843}
1844
1845static s32
1846brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
1847 u8 *mac, struct station_info *sinfo)
1848{
1849 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1850 struct brcmf_scb_val_le scb_val;
1851 int rssi;
1852 s32 rate;
1853 s32 err = 0;
1854 u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID);
1855
1856 WL_TRACE("Enter\n");
1857 if (!check_sys_up(wiphy))
1858 return -EIO;
1859
1860 if (memcmp(mac, bssid, ETH_ALEN)) {
1861 WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X"
1862 "wl_bssid-%X:%X:%X:%X:%X:%X\n",
1863 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
1864 bssid[0], bssid[1], bssid[2], bssid[3],
1865 bssid[4], bssid[5]);
1866 err = -ENOENT;
1867 goto done;
1868 }
1869
1870 /* Report the current tx rate */
1871 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate);
1872 if (err) {
1873 WL_ERR("Could not get rate (%d)\n", err);
1874 } else {
1875 sinfo->filled |= STATION_INFO_TX_BITRATE;
1876 sinfo->txrate.legacy = rate * 5;
1877 WL_CONN("Rate %d Mbps\n", rate / 2);
1878 }
1879
1880 if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
1881 scb_val.val = cpu_to_le32(0);
1882 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
1883 sizeof(struct brcmf_scb_val_le));
1884 if (err)
1885 WL_ERR("Could not get rssi (%d)\n", err);
1886
1887 rssi = le32_to_cpu(scb_val.val);
1888 sinfo->filled |= STATION_INFO_SIGNAL;
1889 sinfo->signal = rssi;
1890 WL_CONN("RSSI %d dBm\n", rssi);
1891 }
1892
1893done:
1894 WL_TRACE("Exit\n");
1895 return err;
1896}
1897
1898static s32
1899brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
1900 bool enabled, s32 timeout)
1901{
1902 s32 pm;
1903 s32 err = 0;
1904 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1905
1906 WL_TRACE("Enter\n");
1907
1908 /*
1909 * Powersave enable/disable request is coming from the
1910 * cfg80211 even before the interface is up. In that
1911 * scenario, driver will be storing the power save
1912 * preference in cfg_priv struct to apply this to
1913 * FW later while initializing the dongle
1914 */
1915 cfg_priv->pwr_save = enabled;
1916 if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
1917
1918 WL_INFO("Device is not ready,"
1919 "storing the value in cfg_priv struct\n");
1920 goto done;
1921 }
1922
1923 pm = enabled ? PM_FAST : PM_OFF;
1924 WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
1925
1926 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm);
1927 if (err) {
1928 if (err == -ENODEV)
1929 WL_ERR("net_device is not ready yet\n");
1930 else
1931 WL_ERR("error (%d)\n", err);
1932 }
1933done:
1934 WL_TRACE("Exit\n");
1935 return err;
1936}
1937
1938static s32
1939brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
1940 const u8 *addr,
1941 const struct cfg80211_bitrate_mask *mask)
1942{
1943 struct brcm_rateset_le rateset_le;
1944 s32 rate;
1945 s32 val;
1946 s32 err_bg;
1947 s32 err_a;
1948 u32 legacy;
1949 s32 err = 0;
1950
1951 WL_TRACE("Enter\n");
1952 if (!check_sys_up(wiphy))
1953 return -EIO;
1954
1955 /* addr param is always NULL. ignore it */
1956 /* Get current rateset */
1957 err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le,
1958 sizeof(rateset_le));
1959 if (err) {
1960 WL_ERR("could not get current rateset (%d)\n", err);
1961 goto done;
1962 }
1963
1964 legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
1965 if (!legacy)
1966 legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
1967 0xFFFF);
1968
1969 val = wl_g_rates[legacy - 1].bitrate * 100000;
1970
1971 if (val < le32_to_cpu(rateset_le.count))
1972 /* Select rate by rateset index */
1973 rate = rateset_le.rates[val] & 0x7f;
1974 else
1975 /* Specified rate in bps */
1976 rate = val / 500000;
1977
1978 WL_CONN("rate %d mbps\n", rate / 2);
1979
1980 /*
1981 *
1982 * Set rate override,
1983 * Since the is a/b/g-blind, both a/bg_rate are enforced.
1984 */
1985 err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate);
1986 err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate);
1987 if (err_bg && err_a) {
1988 WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
1989 err = err_bg | err_a;
1990 }
1991
1992done:
1993 WL_TRACE("Exit\n");
1994 return err;
1995}
1996
1997static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
Roland Vossend34bf642011-10-18 14:03:01 +02001998 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001999{
2000 struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
2001 struct ieee80211_channel *notify_channel;
2002 struct cfg80211_bss *bss;
2003 struct ieee80211_supported_band *band;
2004 s32 err = 0;
2005 u16 channel;
2006 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002007 u16 notify_capability;
2008 u16 notify_interval;
2009 u8 *notify_ie;
2010 size_t notify_ielen;
2011 s32 notify_signal;
2012
2013 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
2014 WL_ERR("Bss info is larger than buffer. Discarding\n");
2015 return 0;
2016 }
2017
2018 channel = bi->ctl_ch ? bi->ctl_ch :
2019 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2020
2021 if (channel <= CH_MAX_2G_CHANNEL)
2022 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2023 else
2024 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2025
2026 freq = ieee80211_channel_to_frequency(channel, band->band);
2027 notify_channel = ieee80211_get_channel(wiphy, freq);
2028
Arend van Spriel5b435de2011-10-05 13:19:03 +02002029 notify_capability = le16_to_cpu(bi->capability);
2030 notify_interval = le16_to_cpu(bi->beacon_period);
2031 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2032 notify_ielen = le32_to_cpu(bi->ie_length);
2033 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2034
2035 WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
2036 bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
2037 bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
2038 WL_CONN("Channel: %d(%d)\n", channel, freq);
2039 WL_CONN("Capability: %X\n", notify_capability);
2040 WL_CONN("Beacon interval: %d\n", notify_interval);
2041 WL_CONN("Signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002042
2043 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002044 0, notify_capability, notify_interval, notify_ie,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002045 notify_ielen, notify_signal, GFP_KERNEL);
2046
Franky Line78946e2011-11-10 20:30:34 +01002047 if (!bss)
2048 return -ENOMEM;
2049
2050 cfg80211_put_bss(bss);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002051
2052 return err;
2053}
2054
Roland Vossen6f09be02011-10-18 14:03:02 +02002055static struct brcmf_bss_info_le *
2056next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2057{
2058 if (bss == NULL)
2059 return list->bss_info_le;
2060 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2061 le32_to_cpu(bss->length));
2062}
2063
Arend van Spriel5b435de2011-10-05 13:19:03 +02002064static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
2065{
2066 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002067 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002068 s32 err = 0;
2069 int i;
2070
2071 bss_list = cfg_priv->bss_list;
2072 if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
2073 WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
2074 bss_list->version);
2075 return -EOPNOTSUPP;
2076 }
2077 WL_SCAN("scanned AP count (%d)\n", bss_list->count);
2078 for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002079 bi = next_bss_le(bss_list, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002080 err = brcmf_inform_single_bss(cfg_priv, bi);
2081 if (err)
2082 break;
2083 }
2084 return err;
2085}
2086
2087static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
2088 struct net_device *ndev, const u8 *bssid)
2089{
2090 struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
2091 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002092 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002093 struct ieee80211_supported_band *band;
Franky Line78946e2011-11-10 20:30:34 +01002094 struct cfg80211_bss *bss;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002095 u8 *buf = NULL;
2096 s32 err = 0;
2097 u16 channel;
2098 u32 freq;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002099 u16 notify_capability;
2100 u16 notify_interval;
2101 u8 *notify_ie;
2102 size_t notify_ielen;
2103 s32 notify_signal;
2104
2105 WL_TRACE("Enter\n");
2106
2107 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2108 if (buf == NULL) {
2109 err = -ENOMEM;
2110 goto CleanUp;
2111 }
2112
2113 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2114
2115 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
2116 if (err) {
2117 WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
2118 goto CleanUp;
2119 }
2120
Roland Vossend34bf642011-10-18 14:03:01 +02002121 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002122
2123 channel = bi->ctl_ch ? bi->ctl_ch :
2124 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2125
2126 if (channel <= CH_MAX_2G_CHANNEL)
2127 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2128 else
2129 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2130
2131 freq = ieee80211_channel_to_frequency(channel, band->band);
2132 notify_channel = ieee80211_get_channel(wiphy, freq);
2133
Arend van Spriel5b435de2011-10-05 13:19:03 +02002134 notify_capability = le16_to_cpu(bi->capability);
2135 notify_interval = le16_to_cpu(bi->beacon_period);
2136 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2137 notify_ielen = le32_to_cpu(bi->ie_length);
2138 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2139
2140 WL_CONN("channel: %d(%d)\n", channel, freq);
2141 WL_CONN("capability: %X\n", notify_capability);
2142 WL_CONN("beacon interval: %d\n", notify_interval);
2143 WL_CONN("signal: %d\n", notify_signal);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144
Franky Line78946e2011-11-10 20:30:34 +01002145 bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
Johannes Berg8e6cffb2012-03-13 13:57:03 +01002146 0, notify_capability, notify_interval,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002147 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2148
Franky Line78946e2011-11-10 20:30:34 +01002149 if (!bss) {
2150 err = -ENOMEM;
2151 goto CleanUp;
2152 }
2153
2154 cfg80211_put_bss(bss);
2155
Arend van Spriel5b435de2011-10-05 13:19:03 +02002156CleanUp:
2157
2158 kfree(buf);
2159
2160 WL_TRACE("Exit\n");
2161
2162 return err;
2163}
2164
2165static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv)
2166{
2167 return cfg_priv->conf->mode == WL_MODE_IBSS;
2168}
2169
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002170/*
2171 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2172 * triples, returning a pointer to the substring whose first element
2173 * matches tag
2174 */
2175static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
2176{
2177 struct brcmf_tlv *elt;
2178 int totlen;
2179
2180 elt = (struct brcmf_tlv *) buf;
2181 totlen = buflen;
2182
2183 /* find tagged parameter */
2184 while (totlen >= 2) {
2185 int len = elt->len;
2186
2187 /* validate remaining totlen */
2188 if ((elt->id == key) && (totlen >= (len + 2)))
2189 return elt;
2190
2191 elt = (struct brcmf_tlv *) ((u8 *) elt + (len + 2));
2192 totlen -= (len + 2);
2193 }
2194
2195 return NULL;
2196}
2197
Arend van Spriel5b435de2011-10-05 13:19:03 +02002198static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
2199{
Roland Vossend34bf642011-10-18 14:03:01 +02002200 struct brcmf_bss_info_le *bi;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002201 struct brcmf_ssid *ssid;
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002202 struct brcmf_tlv *tim;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002203 u16 beacon_interval;
2204 u8 dtim_period;
2205 size_t ie_len;
2206 u8 *ie;
2207 s32 err = 0;
2208
2209 WL_TRACE("Enter\n");
2210 if (brcmf_is_ibssmode(cfg_priv))
2211 return err;
2212
2213 ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID);
2214
2215 *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
2216 err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO,
2217 cfg_priv->extra_buf, WL_EXTRA_BUF_MAX);
2218 if (err) {
2219 WL_ERR("Could not get bss info %d\n", err);
2220 goto update_bss_info_out;
2221 }
2222
Roland Vossend34bf642011-10-18 14:03:01 +02002223 bi = (struct brcmf_bss_info_le *)(cfg_priv->extra_buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002224 err = brcmf_inform_single_bss(cfg_priv, bi);
2225 if (err)
2226 goto update_bss_info_out;
2227
2228 ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
2229 ie_len = le32_to_cpu(bi->ie_length);
2230 beacon_interval = le16_to_cpu(bi->beacon_period);
2231
Alwin Beukersf8e4b412011-10-12 20:51:28 +02002232 tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002233 if (tim)
2234 dtim_period = tim->data[1];
2235 else {
2236 /*
2237 * active scan was done so we could not get dtim
2238 * information out of probe response.
2239 * so we speficially query dtim information to dongle.
2240 */
2241 u32 var;
2242 err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv),
2243 "dtim_assoc", &var);
2244 if (err) {
2245 WL_ERR("wl dtim_assoc failed (%d)\n", err);
2246 goto update_bss_info_out;
2247 }
2248 dtim_period = (u8)var;
2249 }
2250
2251 brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT);
2252 brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
2253
2254update_bss_info_out:
2255 WL_TRACE("Exit");
2256 return err;
2257}
2258
2259static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv)
2260{
2261 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
2262 struct brcmf_ssid ssid;
2263
2264 if (cfg_priv->iscan_on) {
2265 iscan->state = WL_ISCAN_STATE_IDLE;
2266
2267 if (iscan->timer_on) {
2268 del_timer_sync(&iscan->timer);
2269 iscan->timer_on = 0;
2270 }
2271
2272 cancel_work_sync(&iscan->work);
2273
2274 /* Abort iscan running in FW */
2275 memset(&ssid, 0, sizeof(ssid));
2276 brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
2277 }
2278}
2279
2280static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
2281 bool aborted)
2282{
2283 struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
2284 struct net_device *ndev = cfg_to_ndev(cfg_priv);
2285
2286 if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
2287 WL_ERR("Scan complete while device not scanning\n");
2288 return;
2289 }
2290 if (cfg_priv->scan_request) {
2291 WL_SCAN("ISCAN Completed scan: %s\n",
2292 aborted ? "Aborted" : "Done");
2293 cfg80211_scan_done(cfg_priv->scan_request, aborted);
2294 brcmf_set_mpc(ndev, 1);
2295 cfg_priv->scan_request = NULL;
2296 }
2297 cfg_priv->iscan_kickstart = false;
2298}
2299
2300static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
2301{
2302 if (iscan->state != WL_ISCAN_STATE_IDLE) {
2303 WL_SCAN("wake up iscan\n");
2304 schedule_work(&iscan->work);
2305 return 0;
2306 }
2307
2308 return -EIO;
2309}
2310
2311static s32
2312brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
2313 struct brcmf_scan_results **bss_list)
2314{
2315 struct brcmf_iscan_results list;
2316 struct brcmf_scan_results *results;
2317 struct brcmf_scan_results_le *results_le;
2318 struct brcmf_iscan_results *list_buf;
2319 s32 err = 0;
2320
2321 memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
2322 list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
2323 results = &list_buf->results;
2324 results_le = &list_buf->results_le;
2325 results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE;
2326 results->version = 0;
2327 results->count = 0;
2328
2329 memset(&list, 0, sizeof(list));
2330 list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
2331 err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list,
2332 BRCMF_ISCAN_RESULTS_FIXED_SIZE,
2333 iscan->scan_buf, WL_ISCAN_BUF_MAX);
2334 if (err) {
2335 WL_ERR("error (%d)\n", err);
2336 return err;
2337 }
2338 results->buflen = le32_to_cpu(results_le->buflen);
2339 results->version = le32_to_cpu(results_le->version);
2340 results->count = le32_to_cpu(results_le->count);
2341 WL_SCAN("results->count = %d\n", results_le->count);
2342 WL_SCAN("results->buflen = %d\n", results_le->buflen);
2343 *status = le32_to_cpu(list_buf->status_le);
2344 WL_SCAN("status = %d\n", *status);
2345 *bss_list = results;
2346
2347 return err;
2348}
2349
2350static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv)
2351{
2352 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
2353 s32 err = 0;
2354
2355 iscan->state = WL_ISCAN_STATE_IDLE;
2356 brcmf_inform_bss(cfg_priv);
2357 brcmf_notify_iscan_complete(iscan, false);
2358
2359 return err;
2360}
2361
2362static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv)
2363{
2364 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
2365 s32 err = 0;
2366
2367 /* Reschedule the timer */
2368 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
2369 iscan->timer_on = 1;
2370
2371 return err;
2372}
2373
2374static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv)
2375{
2376 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
2377 s32 err = 0;
2378
2379 brcmf_inform_bss(cfg_priv);
2380 brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
2381 /* Reschedule the timer */
2382 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
2383 iscan->timer_on = 1;
2384
2385 return err;
2386}
2387
2388static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv)
2389{
2390 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
2391 s32 err = 0;
2392
2393 iscan->state = WL_ISCAN_STATE_IDLE;
2394 brcmf_notify_iscan_complete(iscan, true);
2395
2396 return err;
2397}
2398
2399static void brcmf_cfg80211_iscan_handler(struct work_struct *work)
2400{
2401 struct brcmf_cfg80211_iscan_ctrl *iscan =
2402 container_of(work, struct brcmf_cfg80211_iscan_ctrl,
2403 work);
2404 struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
2405 struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
2406 u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
2407
2408 if (iscan->timer_on) {
2409 del_timer_sync(&iscan->timer);
2410 iscan->timer_on = 0;
2411 }
2412
2413 if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) {
2414 status = BRCMF_SCAN_RESULTS_ABORTED;
2415 WL_ERR("Abort iscan\n");
2416 }
2417
2418 el->handler[status](cfg_priv);
2419}
2420
2421static void brcmf_iscan_timer(unsigned long data)
2422{
2423 struct brcmf_cfg80211_iscan_ctrl *iscan =
2424 (struct brcmf_cfg80211_iscan_ctrl *)data;
2425
2426 if (iscan) {
2427 iscan->timer_on = 0;
2428 WL_SCAN("timer expired\n");
2429 brcmf_wakeup_iscan(iscan);
2430 }
2431}
2432
2433static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv)
2434{
2435 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
2436
2437 if (cfg_priv->iscan_on) {
2438 iscan->state = WL_ISCAN_STATE_IDLE;
2439 INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
2440 }
2441
2442 return 0;
2443}
2444
2445static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
2446{
2447 memset(el, 0, sizeof(*el));
2448 el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
2449 el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
2450 el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
2451 el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
2452 el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
2453}
2454
2455static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
2456{
2457 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
2458 int err = 0;
2459
2460 if (cfg_priv->iscan_on) {
2461 iscan->ndev = cfg_to_ndev(cfg_priv);
2462 brcmf_init_iscan_eloop(&iscan->el);
2463 iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
2464 init_timer(&iscan->timer);
2465 iscan->timer.data = (unsigned long) iscan;
2466 iscan->timer.function = brcmf_iscan_timer;
2467 err = brcmf_invoke_iscan(cfg_priv);
2468 if (!err)
2469 iscan->data = cfg_priv;
2470 }
2471
2472 return err;
2473}
2474
Alexandre Oliva5addc0d2012-01-16 14:00:12 -05002475static __always_inline void brcmf_delay(u32 ms)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002476{
2477 if (ms < 1000 / HZ) {
2478 cond_resched();
2479 mdelay(ms);
2480 } else {
2481 msleep(ms);
2482 }
2483}
2484
2485static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
2486{
2487 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
2488
2489 /*
2490 * Check for WL_STATUS_READY before any function call which
2491 * could result is bus access. Don't block the resume for
2492 * any driver error conditions
2493 */
2494 WL_TRACE("Enter\n");
2495
2496 if (test_bit(WL_STATUS_READY, &cfg_priv->status))
2497 brcmf_invoke_iscan(wiphy_to_cfg(wiphy));
2498
2499 WL_TRACE("Exit\n");
2500 return 0;
2501}
2502
2503static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
2504 struct cfg80211_wowlan *wow)
2505{
2506 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
2507 struct net_device *ndev = cfg_to_ndev(cfg_priv);
2508
2509 WL_TRACE("Enter\n");
2510
2511 /*
2512 * Check for WL_STATUS_READY before any function call which
2513 * could result is bus access. Don't block the suspend for
2514 * any driver error conditions
2515 */
2516
2517 /*
2518 * While going to suspend if associated with AP disassociate
2519 * from AP to save power while system is in suspended state
2520 */
2521 if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) ||
2522 test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
2523 test_bit(WL_STATUS_READY, &cfg_priv->status)) {
2524 WL_INFO("Disassociating from AP"
2525 " while entering suspend state\n");
2526 brcmf_link_down(cfg_priv);
2527
2528 /*
2529 * 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);
2534 }
2535
2536 set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
2537 if (test_bit(WL_STATUS_READY, &cfg_priv->status))
2538 brcmf_term_iscan(cfg_priv);
2539
2540 if (cfg_priv->scan_request) {
2541 /* Indidate scan abort to cfg80211 layer */
2542 WL_INFO("Terminating scan in progress\n");
2543 cfg80211_scan_done(cfg_priv->scan_request, true);
2544 cfg_priv->scan_request = NULL;
2545 }
2546 clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
2547 clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
2548
2549 /* Turn off watchdog timer */
2550 if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
2551 WL_INFO("Enable MPC\n");
2552 brcmf_set_mpc(ndev, 1);
2553 }
2554
2555 WL_TRACE("Exit\n");
2556
2557 return 0;
2558}
2559
2560static __used s32
2561brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len)
2562{
2563 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
2564 u32 buflen;
2565
Alwin Beukers53a22772011-10-12 20:51:30 +02002566 buflen = brcmf_c_mkiovar(name, buf, len, cfg_priv->dcmd_buf,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002567 WL_DCMD_LEN_MAX);
2568 BUG_ON(!buflen);
2569
2570 return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf,
2571 buflen);
2572}
2573
2574static s32
2575brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf,
2576 s32 buf_len)
2577{
2578 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
2579 u32 len;
2580 s32 err = 0;
2581
Alwin Beukers53a22772011-10-12 20:51:30 +02002582 len = brcmf_c_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002583 WL_DCMD_LEN_MAX);
2584 BUG_ON(!len);
2585 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf,
2586 WL_DCMD_LEN_MAX);
2587 if (err) {
2588 WL_ERR("error (%d)\n", err);
2589 return err;
2590 }
2591 memcpy(buf, cfg_priv->dcmd_buf, buf_len);
2592
2593 return err;
2594}
2595
2596static __used s32
2597brcmf_update_pmklist(struct net_device *ndev,
2598 struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
2599{
2600 int i, j;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002601 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002602
Arend van Spriel40c8e952011-10-12 20:51:20 +02002603 pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
2604
2605 WL_CONN("No of elements %d\n", pmkid_len);
2606 for (i = 0; i < pmkid_len; i++) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002607 WL_CONN("PMKID[%d]: %pM =\n", i,
2608 &pmk_list->pmkids.pmkid[i].BSSID);
2609 for (j = 0; j < WLAN_PMKID_LEN; j++)
2610 WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
2611 }
2612
2613 if (!err)
2614 brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list,
2615 sizeof(*pmk_list));
2616
2617 return err;
2618}
2619
2620static s32
2621brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2622 struct cfg80211_pmksa *pmksa)
2623{
2624 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
2625 struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids;
2626 s32 err = 0;
2627 int i;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002628 int pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002629
2630 WL_TRACE("Enter\n");
2631 if (!check_sys_up(wiphy))
2632 return -EIO;
2633
Arend van Spriel40c8e952011-10-12 20:51:20 +02002634 pmkid_len = le32_to_cpu(pmkids->npmkid);
2635 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002636 if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
2637 break;
2638 if (i < WL_NUM_PMKIDS_MAX) {
2639 memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
2640 memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
Arend van Spriel40c8e952011-10-12 20:51:20 +02002641 if (i == pmkid_len) {
2642 pmkid_len++;
2643 pmkids->npmkid = cpu_to_le32(pmkid_len);
2644 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002645 } else
2646 err = -EINVAL;
2647
2648 WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
Arend van Spriel40c8e952011-10-12 20:51:20 +02002649 pmkids->pmkid[pmkid_len].BSSID);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002650 for (i = 0; i < WLAN_PMKID_LEN; i++)
Arend van Spriel40c8e952011-10-12 20:51:20 +02002651 WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002652
2653 err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
2654
2655 WL_TRACE("Exit\n");
2656 return err;
2657}
2658
2659static s32
2660brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
2661 struct cfg80211_pmksa *pmksa)
2662{
2663 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
2664 struct pmkid_list pmkid;
2665 s32 err = 0;
Arend van Spriel40c8e952011-10-12 20:51:20 +02002666 int i, pmkid_len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002667
2668 WL_TRACE("Enter\n");
2669 if (!check_sys_up(wiphy))
2670 return -EIO;
2671
2672 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
2673 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2674
2675 WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
2676 &pmkid.pmkid[0].BSSID);
2677 for (i = 0; i < WLAN_PMKID_LEN; i++)
2678 WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
2679
Arend van Spriel40c8e952011-10-12 20:51:20 +02002680 pmkid_len = le32_to_cpu(cfg_priv->pmk_list->pmkids.npmkid);
2681 for (i = 0; i < pmkid_len; i++)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002682 if (!memcmp
2683 (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID,
2684 ETH_ALEN))
2685 break;
2686
Arend van Spriel40c8e952011-10-12 20:51:20 +02002687 if ((pmkid_len > 0)
2688 && (i < pmkid_len)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002689 memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0,
2690 sizeof(struct pmkid));
Arend van Spriel40c8e952011-10-12 20:51:20 +02002691 for (; i < (pmkid_len - 1); i++) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002692 memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID,
2693 &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID,
2694 ETH_ALEN);
2695 memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID,
2696 &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID,
2697 WLAN_PMKID_LEN);
2698 }
Arend van Spriel40c8e952011-10-12 20:51:20 +02002699 cfg_priv->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002700 } else
2701 err = -EINVAL;
2702
2703 err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
2704
2705 WL_TRACE("Exit\n");
2706 return err;
2707
2708}
2709
2710static s32
2711brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
2712{
2713 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
2714 s32 err = 0;
2715
2716 WL_TRACE("Enter\n");
2717 if (!check_sys_up(wiphy))
2718 return -EIO;
2719
2720 memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list));
2721 err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
2722
2723 WL_TRACE("Exit\n");
2724 return err;
2725
2726}
2727
2728static struct cfg80211_ops wl_cfg80211_ops = {
2729 .change_virtual_intf = brcmf_cfg80211_change_iface,
2730 .scan = brcmf_cfg80211_scan,
2731 .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
2732 .join_ibss = brcmf_cfg80211_join_ibss,
2733 .leave_ibss = brcmf_cfg80211_leave_ibss,
2734 .get_station = brcmf_cfg80211_get_station,
2735 .set_tx_power = brcmf_cfg80211_set_tx_power,
2736 .get_tx_power = brcmf_cfg80211_get_tx_power,
2737 .add_key = brcmf_cfg80211_add_key,
2738 .del_key = brcmf_cfg80211_del_key,
2739 .get_key = brcmf_cfg80211_get_key,
2740 .set_default_key = brcmf_cfg80211_config_default_key,
2741 .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
2742 .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
2743 .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
2744 .connect = brcmf_cfg80211_connect,
2745 .disconnect = brcmf_cfg80211_disconnect,
2746 .suspend = brcmf_cfg80211_suspend,
2747 .resume = brcmf_cfg80211_resume,
2748 .set_pmksa = brcmf_cfg80211_set_pmksa,
2749 .del_pmksa = brcmf_cfg80211_del_pmksa,
2750 .flush_pmksa = brcmf_cfg80211_flush_pmksa
2751};
2752
2753static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
2754{
2755 s32 err = 0;
2756
2757 switch (mode) {
2758 case WL_MODE_BSS:
2759 return NL80211_IFTYPE_STATION;
2760 case WL_MODE_IBSS:
2761 return NL80211_IFTYPE_ADHOC;
2762 default:
2763 return NL80211_IFTYPE_UNSPECIFIED;
2764 }
2765
2766 return err;
2767}
2768
2769static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
2770 struct device *ndev)
2771{
2772 struct wireless_dev *wdev;
2773 s32 err = 0;
2774
2775 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2776 if (!wdev)
2777 return ERR_PTR(-ENOMEM);
2778
2779 wdev->wiphy =
2780 wiphy_new(&wl_cfg80211_ops,
2781 sizeof(struct brcmf_cfg80211_priv) + sizeof_iface);
2782 if (!wdev->wiphy) {
Joe Perchesbfeb4db2012-01-15 00:38:45 -08002783 WL_ERR("Could not allocate wiphy device\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002784 err = -ENOMEM;
2785 goto wiphy_new_out;
2786 }
2787 set_wiphy_dev(wdev->wiphy, ndev);
2788 wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
2789 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
2790 wdev->wiphy->interface_modes =
2791 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
2792 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
2793 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
2794 * it as 11a by default.
2795 * This will be updated with
2796 * 11n phy tables in
2797 * "ifconfig up"
2798 * if phy has 11n capability
2799 */
2800 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
2801 wdev->wiphy->cipher_suites = __wl_cipher_suites;
2802 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
2803 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
2804 * save mode
2805 * by default
2806 */
2807 err = wiphy_register(wdev->wiphy);
2808 if (err < 0) {
Joe Perchesbfeb4db2012-01-15 00:38:45 -08002809 WL_ERR("Could not register wiphy device (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002810 goto wiphy_register_out;
2811 }
2812 return wdev;
2813
2814wiphy_register_out:
2815 wiphy_free(wdev->wiphy);
2816
2817wiphy_new_out:
2818 kfree(wdev);
2819
2820 return ERR_PTR(err);
2821}
2822
2823static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv)
2824{
2825 struct wireless_dev *wdev = cfg_priv->wdev;
2826
2827 if (!wdev) {
2828 WL_ERR("wdev is invalid\n");
2829 return;
2830 }
2831 wiphy_unregister(wdev->wiphy);
2832 wiphy_free(wdev->wiphy);
2833 kfree(wdev);
2834 cfg_priv->wdev = NULL;
2835}
2836
2837static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv,
2838 const struct brcmf_event_msg *e)
2839{
2840 u32 event = be32_to_cpu(e->event_type);
2841 u32 status = be32_to_cpu(e->status);
2842
2843 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
2844 WL_CONN("Processing set ssid\n");
2845 cfg_priv->link_up = true;
2846 return true;
2847 }
2848
2849 return false;
2850}
2851
2852static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv,
2853 const struct brcmf_event_msg *e)
2854{
2855 u32 event = be32_to_cpu(e->event_type);
2856 u16 flags = be16_to_cpu(e->flags);
2857
2858 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
2859 WL_CONN("Processing link down\n");
2860 return true;
2861 }
2862 return false;
2863}
2864
2865static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv,
2866 const struct brcmf_event_msg *e)
2867{
2868 u32 event = be32_to_cpu(e->event_type);
2869 u32 status = be32_to_cpu(e->status);
2870
2871 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
2872 WL_CONN("Processing Link %s & no network found\n",
2873 be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
2874 "up" : "down");
2875 return true;
2876 }
2877
2878 if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
2879 WL_CONN("Processing connecting & no network found\n");
2880 return true;
2881 }
2882
2883 return false;
2884}
2885
2886static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
2887{
2888 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
2889
2890 kfree(conn_info->req_ie);
2891 conn_info->req_ie = NULL;
2892 conn_info->req_ie_len = 0;
2893 kfree(conn_info->resp_ie);
2894 conn_info->resp_ie = NULL;
2895 conn_info->resp_ie_len = 0;
2896}
2897
2898static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
2899{
2900 struct net_device *ndev = cfg_to_ndev(cfg_priv);
Arend van Sprielc4e382d2011-10-12 20:51:21 +02002901 struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002902 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
2903 u32 req_len;
2904 u32 resp_len;
2905 s32 err = 0;
2906
2907 brcmf_clear_assoc_ies(cfg_priv);
2908
2909 err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf,
2910 WL_ASSOC_INFO_MAX);
2911 if (err) {
2912 WL_ERR("could not get assoc info (%d)\n", err);
2913 return err;
2914 }
Arend van Sprielc4e382d2011-10-12 20:51:21 +02002915 assoc_info =
2916 (struct brcmf_cfg80211_assoc_ielen_le *)cfg_priv->extra_buf;
2917 req_len = le32_to_cpu(assoc_info->req_len);
2918 resp_len = le32_to_cpu(assoc_info->resp_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002919 if (req_len) {
2920 err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies",
2921 cfg_priv->extra_buf,
2922 WL_ASSOC_INFO_MAX);
2923 if (err) {
2924 WL_ERR("could not get assoc req (%d)\n", err);
2925 return err;
2926 }
2927 conn_info->req_ie_len = req_len;
2928 conn_info->req_ie =
2929 kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len,
2930 GFP_KERNEL);
2931 } else {
2932 conn_info->req_ie_len = 0;
2933 conn_info->req_ie = NULL;
2934 }
2935 if (resp_len) {
2936 err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies",
2937 cfg_priv->extra_buf,
2938 WL_ASSOC_INFO_MAX);
2939 if (err) {
2940 WL_ERR("could not get assoc resp (%d)\n", err);
2941 return err;
2942 }
2943 conn_info->resp_ie_len = resp_len;
2944 conn_info->resp_ie =
2945 kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len,
2946 GFP_KERNEL);
2947 } else {
2948 conn_info->resp_ie_len = 0;
2949 conn_info->resp_ie = NULL;
2950 }
2951 WL_CONN("req len (%d) resp len (%d)\n",
2952 conn_info->req_ie_len, conn_info->resp_ie_len);
2953
2954 return err;
2955}
2956
2957static s32
2958brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
2959 struct net_device *ndev,
2960 const struct brcmf_event_msg *e)
2961{
2962 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
2963 struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
2964 struct brcmf_channel_info_le channel_le;
2965 struct ieee80211_channel *notify_channel;
2966 struct ieee80211_supported_band *band;
2967 u32 freq;
2968 s32 err = 0;
2969 u32 target_channel;
2970
2971 WL_TRACE("Enter\n");
2972
2973 brcmf_get_assoc_ies(cfg_priv);
2974 brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID);
2975 brcmf_update_bss_info(cfg_priv);
2976
2977 brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le,
2978 sizeof(channel_le));
2979
2980 target_channel = le32_to_cpu(channel_le.target_channel);
2981 WL_CONN("Roamed to channel %d\n", target_channel);
2982
2983 if (target_channel <= CH_MAX_2G_CHANNEL)
2984 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2985 else
2986 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2987
2988 freq = ieee80211_channel_to_frequency(target_channel, band->band);
2989 notify_channel = ieee80211_get_channel(wiphy, freq);
2990
2991 cfg80211_roamed(ndev, notify_channel,
2992 (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID),
2993 conn_info->req_ie, conn_info->req_ie_len,
2994 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
2995 WL_CONN("Report roaming result\n");
2996
2997 set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
2998 WL_TRACE("Exit\n");
2999 return err;
3000}
3001
3002static s32
3003brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
3004 struct net_device *ndev, const struct brcmf_event_msg *e,
3005 bool completed)
3006{
3007 struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
3008 s32 err = 0;
3009
3010 WL_TRACE("Enter\n");
3011
3012 if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
3013 if (completed) {
3014 brcmf_get_assoc_ies(cfg_priv);
3015 brcmf_update_prof(cfg_priv, NULL, &e->addr,
3016 WL_PROF_BSSID);
3017 brcmf_update_bss_info(cfg_priv);
3018 }
3019 cfg80211_connect_result(ndev,
3020 (u8 *)brcmf_read_prof(cfg_priv,
3021 WL_PROF_BSSID),
3022 conn_info->req_ie,
3023 conn_info->req_ie_len,
3024 conn_info->resp_ie,
3025 conn_info->resp_ie_len,
3026 completed ? WLAN_STATUS_SUCCESS :
3027 WLAN_STATUS_AUTH_TIMEOUT,
3028 GFP_KERNEL);
3029 if (completed)
3030 set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
3031 WL_CONN("Report connect result - connection %s\n",
3032 completed ? "succeeded" : "failed");
3033 }
3034 WL_TRACE("Exit\n");
3035 return err;
3036}
3037
3038static s32
3039brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv,
3040 struct net_device *ndev,
3041 const struct brcmf_event_msg *e, void *data)
3042{
3043 s32 err = 0;
3044
3045 if (brcmf_is_linkup(cfg_priv, e)) {
3046 WL_CONN("Linkup\n");
3047 if (brcmf_is_ibssmode(cfg_priv)) {
3048 brcmf_update_prof(cfg_priv, NULL, (void *)e->addr,
3049 WL_PROF_BSSID);
3050 wl_inform_ibss(cfg_priv, ndev, e->addr);
3051 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
3052 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
3053 set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
3054 } else
3055 brcmf_bss_connect_done(cfg_priv, ndev, e, true);
3056 } else if (brcmf_is_linkdown(cfg_priv, e)) {
3057 WL_CONN("Linkdown\n");
3058 if (brcmf_is_ibssmode(cfg_priv)) {
3059 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
3060 if (test_and_clear_bit(WL_STATUS_CONNECTED,
3061 &cfg_priv->status))
3062 brcmf_link_down(cfg_priv);
3063 } else {
3064 brcmf_bss_connect_done(cfg_priv, ndev, e, false);
3065 if (test_and_clear_bit(WL_STATUS_CONNECTED,
3066 &cfg_priv->status)) {
3067 cfg80211_disconnected(ndev, 0, NULL, 0,
3068 GFP_KERNEL);
3069 brcmf_link_down(cfg_priv);
3070 }
3071 }
3072 brcmf_init_prof(cfg_priv->profile);
3073 } else if (brcmf_is_nonetwork(cfg_priv, e)) {
3074 if (brcmf_is_ibssmode(cfg_priv))
3075 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
3076 else
3077 brcmf_bss_connect_done(cfg_priv, ndev, e, false);
3078 }
3079
3080 return err;
3081}
3082
3083static s32
3084brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv,
3085 struct net_device *ndev,
3086 const struct brcmf_event_msg *e, void *data)
3087{
3088 s32 err = 0;
3089 u32 event = be32_to_cpu(e->event_type);
3090 u32 status = be32_to_cpu(e->status);
3091
3092 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
3093 if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status))
3094 brcmf_bss_roaming_done(cfg_priv, ndev, e);
3095 else
3096 brcmf_bss_connect_done(cfg_priv, ndev, e, true);
3097 }
3098
3099 return err;
3100}
3101
3102static s32
3103brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv,
3104 struct net_device *ndev,
3105 const struct brcmf_event_msg *e, void *data)
3106{
3107 u16 flags = be16_to_cpu(e->flags);
3108 enum nl80211_key_type key_type;
3109
3110 if (flags & BRCMF_EVENT_MSG_GROUP)
3111 key_type = NL80211_KEYTYPE_GROUP;
3112 else
3113 key_type = NL80211_KEYTYPE_PAIRWISE;
3114
3115 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
3116 NULL, GFP_KERNEL);
3117
3118 return 0;
3119}
3120
3121static s32
3122brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv,
3123 struct net_device *ndev,
3124 const struct brcmf_event_msg *e, void *data)
3125{
3126 struct brcmf_channel_info_le channel_inform_le;
3127 struct brcmf_scan_results_le *bss_list_le;
3128 u32 len = WL_SCAN_BUF_MAX;
3129 s32 err = 0;
3130 bool scan_abort = false;
3131 u32 scan_channel;
3132
3133 WL_TRACE("Enter\n");
3134
3135 if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) {
3136 WL_TRACE("Exit\n");
3137 return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv));
3138 }
3139
3140 if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
3141 WL_ERR("Scan complete while device not scanning\n");
3142 scan_abort = true;
3143 err = -EINVAL;
3144 goto scan_done_out;
3145 }
3146
3147 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le,
3148 sizeof(channel_inform_le));
3149 if (err) {
3150 WL_ERR("scan busy (%d)\n", err);
3151 scan_abort = true;
3152 goto scan_done_out;
3153 }
3154 scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
3155 if (scan_channel)
3156 WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
3157 cfg_priv->bss_list = cfg_priv->scan_results;
3158 bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list;
3159
3160 memset(cfg_priv->scan_results, 0, len);
3161 bss_list_le->buflen = cpu_to_le32(len);
3162 err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS,
3163 cfg_priv->scan_results, len);
3164 if (err) {
3165 WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
3166 err = -EINVAL;
3167 scan_abort = true;
3168 goto scan_done_out;
3169 }
3170 cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
3171 cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version);
3172 cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count);
3173
3174 err = brcmf_inform_bss(cfg_priv);
3175 if (err) {
3176 scan_abort = true;
3177 goto scan_done_out;
3178 }
3179
3180scan_done_out:
3181 if (cfg_priv->scan_request) {
3182 WL_SCAN("calling cfg80211_scan_done\n");
3183 cfg80211_scan_done(cfg_priv->scan_request, scan_abort);
3184 brcmf_set_mpc(ndev, 1);
3185 cfg_priv->scan_request = NULL;
3186 }
3187
3188 WL_TRACE("Exit\n");
3189
3190 return err;
3191}
3192
3193static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
3194{
3195 conf->mode = (u32)-1;
3196 conf->frag_threshold = (u32)-1;
3197 conf->rts_threshold = (u32)-1;
3198 conf->retry_short = (u32)-1;
3199 conf->retry_long = (u32)-1;
3200 conf->tx_power = -1;
3201}
3202
3203static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
3204{
3205 memset(el, 0, sizeof(*el));
3206 el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;
3207 el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
3208 el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
3209 el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
3210 el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
3211}
3212
3213static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
3214{
3215 kfree(cfg_priv->scan_results);
3216 cfg_priv->scan_results = NULL;
3217 kfree(cfg_priv->bss_info);
3218 cfg_priv->bss_info = NULL;
3219 kfree(cfg_priv->conf);
3220 cfg_priv->conf = NULL;
3221 kfree(cfg_priv->profile);
3222 cfg_priv->profile = NULL;
3223 kfree(cfg_priv->scan_req_int);
3224 cfg_priv->scan_req_int = NULL;
3225 kfree(cfg_priv->dcmd_buf);
3226 cfg_priv->dcmd_buf = NULL;
3227 kfree(cfg_priv->extra_buf);
3228 cfg_priv->extra_buf = NULL;
3229 kfree(cfg_priv->iscan);
3230 cfg_priv->iscan = NULL;
3231 kfree(cfg_priv->pmk_list);
3232 cfg_priv->pmk_list = NULL;
3233}
3234
3235static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
3236{
3237 cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
3238 if (!cfg_priv->scan_results)
3239 goto init_priv_mem_out;
3240 cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL);
3241 if (!cfg_priv->conf)
3242 goto init_priv_mem_out;
3243 cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL);
3244 if (!cfg_priv->profile)
3245 goto init_priv_mem_out;
3246 cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
3247 if (!cfg_priv->bss_info)
3248 goto init_priv_mem_out;
3249 cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int),
3250 GFP_KERNEL);
3251 if (!cfg_priv->scan_req_int)
3252 goto init_priv_mem_out;
3253 cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
3254 if (!cfg_priv->dcmd_buf)
3255 goto init_priv_mem_out;
3256 cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
3257 if (!cfg_priv->extra_buf)
3258 goto init_priv_mem_out;
3259 cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL);
3260 if (!cfg_priv->iscan)
3261 goto init_priv_mem_out;
3262 cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL);
3263 if (!cfg_priv->pmk_list)
3264 goto init_priv_mem_out;
3265
3266 return 0;
3267
3268init_priv_mem_out:
3269 brcmf_deinit_priv_mem(cfg_priv);
3270
3271 return -ENOMEM;
3272}
3273
3274/*
3275* retrieve first queued event from head
3276*/
3277
3278static struct brcmf_cfg80211_event_q *brcmf_deq_event(
3279 struct brcmf_cfg80211_priv *cfg_priv)
3280{
3281 struct brcmf_cfg80211_event_q *e = NULL;
3282
3283 spin_lock_irq(&cfg_priv->evt_q_lock);
3284 if (!list_empty(&cfg_priv->evt_q_list)) {
3285 e = list_first_entry(&cfg_priv->evt_q_list,
3286 struct brcmf_cfg80211_event_q, evt_q_list);
3287 list_del(&e->evt_q_list);
3288 }
3289 spin_unlock_irq(&cfg_priv->evt_q_lock);
3290
3291 return e;
3292}
3293
3294/*
Arend van Sprielbcbec9e2012-02-09 21:09:06 +01003295* push event to tail of the queue
3296*
3297* remark: this function may not sleep as it is called in atomic context.
Arend van Spriel5b435de2011-10-05 13:19:03 +02003298*/
3299
3300static s32
3301brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
3302 const struct brcmf_event_msg *msg)
3303{
3304 struct brcmf_cfg80211_event_q *e;
3305 s32 err = 0;
Arend van Sprielcf440662012-02-09 21:09:07 +01003306 ulong flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003307
Arend van Sprielbcbec9e2012-02-09 21:09:06 +01003308 e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_ATOMIC);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003309 if (!e)
3310 return -ENOMEM;
3311
3312 e->etype = event;
3313 memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
3314
Arend van Sprielcf440662012-02-09 21:09:07 +01003315 spin_lock_irqsave(&cfg_priv->evt_q_lock, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003316 list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
Arend van Sprielcf440662012-02-09 21:09:07 +01003317 spin_unlock_irqrestore(&cfg_priv->evt_q_lock, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003318
3319 return err;
3320}
3321
3322static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
3323{
3324 kfree(e);
3325}
3326
3327static void brcmf_cfg80211_event_handler(struct work_struct *work)
3328{
3329 struct brcmf_cfg80211_priv *cfg_priv =
3330 container_of(work, struct brcmf_cfg80211_priv,
3331 event_work);
3332 struct brcmf_cfg80211_event_q *e;
3333
3334 e = brcmf_deq_event(cfg_priv);
3335 if (unlikely(!e)) {
3336 WL_ERR("event queue empty...\n");
3337 return;
3338 }
3339
3340 do {
3341 WL_INFO("event type (%d)\n", e->etype);
3342 if (cfg_priv->el.handler[e->etype])
3343 cfg_priv->el.handler[e->etype](cfg_priv,
3344 cfg_to_ndev(cfg_priv),
3345 &e->emsg, e->edata);
3346 else
3347 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
3348 brcmf_put_event(e);
3349 } while ((e = brcmf_deq_event(cfg_priv)));
3350
3351}
3352
3353static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv)
3354{
3355 spin_lock_init(&cfg_priv->evt_q_lock);
3356 INIT_LIST_HEAD(&cfg_priv->evt_q_list);
3357}
3358
3359static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv)
3360{
3361 struct brcmf_cfg80211_event_q *e;
3362
3363 spin_lock_irq(&cfg_priv->evt_q_lock);
3364 while (!list_empty(&cfg_priv->evt_q_list)) {
3365 e = list_first_entry(&cfg_priv->evt_q_list,
3366 struct brcmf_cfg80211_event_q, evt_q_list);
3367 list_del(&e->evt_q_list);
3368 kfree(e);
3369 }
3370 spin_unlock_irq(&cfg_priv->evt_q_lock);
3371}
3372
3373static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
3374{
3375 s32 err = 0;
3376
3377 cfg_priv->scan_request = NULL;
3378 cfg_priv->pwr_save = true;
3379 cfg_priv->iscan_on = true; /* iscan on & off switch.
3380 we enable iscan per default */
3381 cfg_priv->roam_on = true; /* roam on & off switch.
3382 we enable roam per default */
3383
3384 cfg_priv->iscan_kickstart = false;
3385 cfg_priv->active_scan = true; /* we do active scan for
3386 specific scan per default */
3387 cfg_priv->dongle_up = false; /* dongle is not up yet */
3388 brcmf_init_eq(cfg_priv);
3389 err = brcmf_init_priv_mem(cfg_priv);
3390 if (err)
3391 return err;
3392 INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler);
3393 brcmf_init_eloop_handler(&cfg_priv->el);
3394 mutex_init(&cfg_priv->usr_sync);
3395 err = brcmf_init_iscan(cfg_priv);
3396 if (err)
3397 return err;
3398 brcmf_init_conf(cfg_priv->conf);
3399 brcmf_init_prof(cfg_priv->profile);
3400 brcmf_link_down(cfg_priv);
3401
3402 return err;
3403}
3404
3405static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv)
3406{
3407 cancel_work_sync(&cfg_priv->event_work);
3408 cfg_priv->dongle_up = false; /* dongle down */
3409 brcmf_flush_eq(cfg_priv);
3410 brcmf_link_down(cfg_priv);
3411 brcmf_term_iscan(cfg_priv);
3412 brcmf_deinit_priv_mem(cfg_priv);
3413}
3414
3415struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
3416 struct device *busdev,
3417 void *data)
3418{
3419 struct wireless_dev *wdev;
3420 struct brcmf_cfg80211_priv *cfg_priv;
3421 struct brcmf_cfg80211_iface *ci;
3422 struct brcmf_cfg80211_dev *cfg_dev;
3423 s32 err = 0;
3424
3425 if (!ndev) {
3426 WL_ERR("ndev is invalid\n");
3427 return NULL;
3428 }
3429 cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL);
3430 if (!cfg_dev)
3431 return NULL;
3432
3433 wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev);
3434 if (IS_ERR(wdev)) {
3435 kfree(cfg_dev);
3436 return NULL;
3437 }
3438
3439 wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
3440 cfg_priv = wdev_to_cfg(wdev);
3441 cfg_priv->wdev = wdev;
3442 cfg_priv->pub = data;
3443 ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci;
3444 ci->cfg_priv = cfg_priv;
3445 ndev->ieee80211_ptr = wdev;
3446 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
3447 wdev->netdev = ndev;
3448 err = wl_init_priv(cfg_priv);
3449 if (err) {
3450 WL_ERR("Failed to init iwm_priv (%d)\n", err);
3451 goto cfg80211_attach_out;
3452 }
3453 brcmf_set_drvdata(cfg_dev, ci);
3454
3455 return cfg_dev;
3456
3457cfg80211_attach_out:
3458 brcmf_free_wdev(cfg_priv);
3459 kfree(cfg_dev);
3460 return NULL;
3461}
3462
3463void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev)
3464{
3465 struct brcmf_cfg80211_priv *cfg_priv;
3466
3467 cfg_priv = brcmf_priv_get(cfg_dev);
3468
3469 wl_deinit_priv(cfg_priv);
3470 brcmf_free_wdev(cfg_priv);
3471 brcmf_set_drvdata(cfg_dev, NULL);
3472 kfree(cfg_dev);
3473}
3474
3475void
3476brcmf_cfg80211_event(struct net_device *ndev,
3477 const struct brcmf_event_msg *e, void *data)
3478{
3479 u32 event_type = be32_to_cpu(e->event_type);
3480 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
3481
3482 if (!brcmf_enq_event(cfg_priv, event_type, e))
3483 schedule_work(&cfg_priv->event_work);
3484}
3485
3486static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
3487{
3488 s32 infra = 0;
3489 s32 err = 0;
3490
3491 switch (iftype) {
3492 case NL80211_IFTYPE_MONITOR:
3493 case NL80211_IFTYPE_WDS:
3494 WL_ERR("type (%d) : currently we do not support this mode\n",
3495 iftype);
3496 err = -EINVAL;
3497 return err;
3498 case NL80211_IFTYPE_ADHOC:
3499 infra = 0;
3500 break;
3501 case NL80211_IFTYPE_STATION:
3502 infra = 1;
3503 break;
3504 default:
3505 err = -EINVAL;
3506 WL_ERR("invalid type (%d)\n", iftype);
3507 return err;
3508 }
3509 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
3510 if (err) {
3511 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
3512 return err;
3513 }
3514
3515 return 0;
3516}
3517
3518static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
3519{
3520 /* Room for "event_msgs" + '\0' + bitvec */
3521 s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
3522 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
3523 s32 err = 0;
3524
3525 WL_TRACE("Enter\n");
3526
3527 /* Setup event_msgs */
Alwin Beukers53a22772011-10-12 20:51:30 +02003528 brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
3529 iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003530 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
3531 if (err) {
3532 WL_ERR("Get event_msgs error (%d)\n", err);
3533 goto dongle_eventmsg_out;
3534 }
3535 memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
3536
3537 setbit(eventmask, BRCMF_E_SET_SSID);
3538 setbit(eventmask, BRCMF_E_ROAM);
3539 setbit(eventmask, BRCMF_E_PRUNE);
3540 setbit(eventmask, BRCMF_E_AUTH);
3541 setbit(eventmask, BRCMF_E_REASSOC);
3542 setbit(eventmask, BRCMF_E_REASSOC_IND);
3543 setbit(eventmask, BRCMF_E_DEAUTH_IND);
3544 setbit(eventmask, BRCMF_E_DISASSOC_IND);
3545 setbit(eventmask, BRCMF_E_DISASSOC);
3546 setbit(eventmask, BRCMF_E_JOIN);
3547 setbit(eventmask, BRCMF_E_ASSOC_IND);
3548 setbit(eventmask, BRCMF_E_PSK_SUP);
3549 setbit(eventmask, BRCMF_E_LINK);
3550 setbit(eventmask, BRCMF_E_NDIS_LINK);
3551 setbit(eventmask, BRCMF_E_MIC_ERROR);
3552 setbit(eventmask, BRCMF_E_PMKID_CACHE);
3553 setbit(eventmask, BRCMF_E_TXFAIL);
3554 setbit(eventmask, BRCMF_E_JOIN_START);
3555 setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
3556
Alwin Beukers53a22772011-10-12 20:51:30 +02003557 brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
3558 iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003559 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
3560 if (err) {
3561 WL_ERR("Set event_msgs error (%d)\n", err);
3562 goto dongle_eventmsg_out;
3563 }
3564
3565dongle_eventmsg_out:
3566 WL_TRACE("Exit\n");
3567 return err;
3568}
3569
3570static s32
3571brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
3572{
3573 s8 iovbuf[32];
Arend van Spriel5b435de2011-10-05 13:19:03 +02003574 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02003575 __le32 roamtrigger[2];
3576 __le32 roam_delta[2];
3577 __le32 bcn_to_le;
3578 __le32 roamvar_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003579
3580 /*
3581 * Setup timeout if Beacons are lost and roam is
3582 * off to report link down
3583 */
3584 if (roamvar) {
Arend van Sprielf588bc02011-10-12 20:51:22 +02003585 bcn_to_le = cpu_to_le32(bcn_timeout);
Alwin Beukers53a22772011-10-12 20:51:30 +02003586 brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le,
Arend van Sprielf588bc02011-10-12 20:51:22 +02003587 sizeof(bcn_to_le), iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003588 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR,
3589 iovbuf, sizeof(iovbuf));
3590 if (err) {
3591 WL_ERR("bcn_timeout error (%d)\n", err);
3592 goto dongle_rom_out;
3593 }
3594 }
3595
3596 /*
3597 * Enable/Disable built-in roaming to allow supplicant
3598 * to take care of roaming
3599 */
3600 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielf588bc02011-10-12 20:51:22 +02003601 roamvar_le = cpu_to_le32(roamvar);
Alwin Beukers53a22772011-10-12 20:51:30 +02003602 brcmf_c_mkiovar("roam_off", (char *)&roamvar_le,
Arend van Sprielf588bc02011-10-12 20:51:22 +02003603 sizeof(roamvar_le), iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003604 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
3605 if (err) {
3606 WL_ERR("roam_off error (%d)\n", err);
3607 goto dongle_rom_out;
3608 }
3609
Arend van Sprielf588bc02011-10-12 20:51:22 +02003610 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
3611 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003612 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER,
3613 (void *)roamtrigger, sizeof(roamtrigger));
3614 if (err) {
3615 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
3616 goto dongle_rom_out;
3617 }
3618
Arend van Sprielf588bc02011-10-12 20:51:22 +02003619 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
3620 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003621 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA,
3622 (void *)roam_delta, sizeof(roam_delta));
3623 if (err) {
3624 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
3625 goto dongle_rom_out;
3626 }
3627
3628dongle_rom_out:
3629 return err;
3630}
3631
3632static s32
3633brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003634 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003635{
3636 s32 err = 0;
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003637 __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time);
3638 __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time);
3639 __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003640
3641 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003642 &scan_assoc_tm_le, sizeof(scan_assoc_tm_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003643 if (err) {
3644 if (err == -EOPNOTSUPP)
3645 WL_INFO("Scan assoc time is not supported\n");
3646 else
3647 WL_ERR("Scan assoc time error (%d)\n", err);
3648 goto dongle_scantime_out;
3649 }
3650 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003651 &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003652 if (err) {
3653 if (err == -EOPNOTSUPP)
3654 WL_INFO("Scan unassoc time is not supported\n");
3655 else
3656 WL_ERR("Scan unassoc time error (%d)\n", err);
3657 goto dongle_scantime_out;
3658 }
3659
3660 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003661 &scan_passive_tm_le, sizeof(scan_passive_tm_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003662 if (err) {
3663 if (err == -EOPNOTSUPP)
3664 WL_INFO("Scan passive time is not supported\n");
3665 else
3666 WL_ERR("Scan passive time error (%d)\n", err);
3667 goto dongle_scantime_out;
3668 }
3669
3670dongle_scantime_out:
3671 return err;
3672}
3673
3674static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv)
3675{
3676 struct wiphy *wiphy;
3677 s32 phy_list;
3678 s8 phy;
3679 s32 err = 0;
3680
3681 err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST,
3682 &phy_list, sizeof(phy_list));
3683 if (err) {
3684 WL_ERR("error (%d)\n", err);
3685 return err;
3686 }
3687
3688 phy = ((char *)&phy_list)[1];
3689 WL_INFO("%c phy\n", phy);
3690 if (phy == 'n' || phy == 'a') {
3691 wiphy = cfg_to_wiphy(cfg_priv);
3692 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
3693 }
3694
3695 return err;
3696}
3697
3698static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv)
3699{
3700 return wl_update_wiphybands(cfg_priv);
3701}
3702
3703static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv)
3704{
3705 struct net_device *ndev;
3706 struct wireless_dev *wdev;
3707 s32 power_mode;
3708 s32 err = 0;
3709
3710 if (cfg_priv->dongle_up)
3711 return err;
3712
3713 ndev = cfg_to_ndev(cfg_priv);
3714 wdev = ndev->ieee80211_ptr;
3715
3716 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
3717 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
3718
3719 err = brcmf_dongle_eventmsg(ndev);
3720 if (err)
3721 goto default_conf_out;
3722
3723 power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF;
3724 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode);
3725 if (err)
3726 goto default_conf_out;
3727 WL_INFO("power save set to %s\n",
3728 (power_mode ? "enabled" : "disabled"));
3729
3730 err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1),
3731 WL_BEACON_TIMEOUT);
3732 if (err)
3733 goto default_conf_out;
3734 err = brcmf_dongle_mode(ndev, wdev->iftype);
3735 if (err && err != -EINPROGRESS)
3736 goto default_conf_out;
3737 err = brcmf_dongle_probecap(cfg_priv);
3738 if (err)
3739 goto default_conf_out;
3740
3741 /* -EINPROGRESS: Call commit handler */
3742
3743default_conf_out:
3744
3745 cfg_priv->dongle_up = true;
3746
3747 return err;
3748
3749}
3750
3751static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv)
3752{
3753 char buf[10+IFNAMSIZ];
3754 struct dentry *fd;
3755 s32 err = 0;
3756
3757 sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name);
3758 cfg_priv->debugfsdir = debugfs_create_dir(buf,
3759 cfg_to_wiphy(cfg_priv)->debugfsdir);
3760
3761 fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir,
3762 (u16 *)&cfg_priv->profile->beacon_interval);
3763 if (!fd) {
3764 err = -ENOMEM;
3765 goto err_out;
3766 }
3767
3768 fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir,
3769 (u8 *)&cfg_priv->profile->dtim_period);
3770 if (!fd) {
3771 err = -ENOMEM;
3772 goto err_out;
3773 }
3774
3775err_out:
3776 return err;
3777}
3778
3779static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv)
3780{
3781 debugfs_remove_recursive(cfg_priv->debugfsdir);
3782 cfg_priv->debugfsdir = NULL;
3783}
3784
3785static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv)
3786{
3787 s32 err = 0;
3788
3789 set_bit(WL_STATUS_READY, &cfg_priv->status);
3790
3791 brcmf_debugfs_add_netdev_params(cfg_priv);
3792
3793 err = brcmf_config_dongle(cfg_priv);
3794 if (err)
3795 return err;
3796
3797 brcmf_invoke_iscan(cfg_priv);
3798
3799 return err;
3800}
3801
3802static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv)
3803{
3804 /*
3805 * While going down, if associated with AP disassociate
3806 * from AP to save power
3807 */
3808 if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) ||
3809 test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
3810 test_bit(WL_STATUS_READY, &cfg_priv->status)) {
3811 WL_INFO("Disassociating from AP");
3812 brcmf_link_down(cfg_priv);
3813
3814 /* Make sure WPA_Supplicant receives all the event
3815 generated due to DISASSOC call to the fw to keep
3816 the state fw and WPA_Supplicant state consistent
3817 */
3818 brcmf_delay(500);
3819 }
3820
3821 set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
3822 brcmf_term_iscan(cfg_priv);
3823 if (cfg_priv->scan_request) {
3824 cfg80211_scan_done(cfg_priv->scan_request, true);
3825 /* May need to perform this to cover rmmod */
3826 /* wl_set_mpc(cfg_to_ndev(wl), 1); */
3827 cfg_priv->scan_request = NULL;
3828 }
3829 clear_bit(WL_STATUS_READY, &cfg_priv->status);
3830 clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
3831 clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
3832
3833 brcmf_debugfs_remove_netdev(cfg_priv);
3834
3835 return 0;
3836}
3837
3838s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev)
3839{
3840 struct brcmf_cfg80211_priv *cfg_priv;
3841 s32 err = 0;
3842
3843 cfg_priv = brcmf_priv_get(cfg_dev);
3844 mutex_lock(&cfg_priv->usr_sync);
3845 err = __brcmf_cfg80211_up(cfg_priv);
3846 mutex_unlock(&cfg_priv->usr_sync);
3847
3848 return err;
3849}
3850
3851s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev)
3852{
3853 struct brcmf_cfg80211_priv *cfg_priv;
3854 s32 err = 0;
3855
3856 cfg_priv = brcmf_priv_get(cfg_dev);
3857 mutex_lock(&cfg_priv->usr_sync);
3858 err = __brcmf_cfg80211_down(cfg_priv);
3859 mutex_unlock(&cfg_priv->usr_sync);
3860
3861 return err;
3862}
3863
3864static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
3865 u8 t, u8 l, u8 *v)
3866{
3867 struct brcmf_cfg80211_ie *ie = &cfg_priv->ie;
3868 s32 err = 0;
3869
3870 if (ie->offset + l + 2 > WL_TLV_INFO_MAX) {
3871 WL_ERR("ei crosses buffer boundary\n");
3872 return -ENOSPC;
3873 }
3874 ie->buf[ie->offset] = t;
3875 ie->buf[ie->offset + 1] = l;
3876 memcpy(&ie->buf[ie->offset + 2], v, l);
3877 ie->offset += l + 2;
3878
3879 return err;
3880}