blob: 73be2c8d4cee54246b9f1c0f89692d388e8b7238 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
18
19#include <linux/kernel.h>
20#include <linux/if_arp.h>
21#include <linux/sched.h>
22#include <linux/kthread.h>
23#include <linux/netdevice.h>
24#include <linux/bitops.h>
25#include <linux/etherdevice.h>
26#include <linux/ieee80211.h>
27#include <linux/uaccess.h>
28#include <net/cfg80211.h>
29
30#include <brcmu_utils.h>
31#include <defs.h>
32#include <brcmu_wifi.h>
33#include "dhd.h"
34#include "wl_cfg80211.h"
35
36#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
37 (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
38
39static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
40
41static u32 brcmf_dbg_level = WL_DBG_ERR;
42
43static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data)
44{
45 dev->driver_data = data;
46}
47
48static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev)
49{
50 void *data = NULL;
51
52 if (dev)
53 data = dev->driver_data;
54 return data;
55}
56
57static
58struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev)
59{
60 struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev);
61 return ci->cfg_priv;
62}
63
64static bool check_sys_up(struct wiphy *wiphy)
65{
66 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
67 if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
68 WL_INFO("device is not ready : status (%d)\n",
69 (int)cfg_priv->status);
70 return false;
71 }
72 return true;
73}
74
75#define CHAN2G(_channel, _freq, _flags) { \
76 .band = IEEE80211_BAND_2GHZ, \
77 .center_freq = (_freq), \
78 .hw_value = (_channel), \
79 .flags = (_flags), \
80 .max_antenna_gain = 0, \
81 .max_power = 30, \
82}
83
84#define CHAN5G(_channel, _flags) { \
85 .band = IEEE80211_BAND_5GHZ, \
86 .center_freq = 5000 + (5 * (_channel)), \
87 .hw_value = (_channel), \
88 .flags = (_flags), \
89 .max_antenna_gain = 0, \
90 .max_power = 30, \
91}
92
93#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
94#define RATETAB_ENT(_rateid, _flags) \
95 { \
96 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
97 .hw_value = (_rateid), \
98 .flags = (_flags), \
99 }
100
101static struct ieee80211_rate __wl_rates[] = {
102 RATETAB_ENT(BRCM_RATE_1M, 0),
103 RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
104 RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
105 RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
106 RATETAB_ENT(BRCM_RATE_6M, 0),
107 RATETAB_ENT(BRCM_RATE_9M, 0),
108 RATETAB_ENT(BRCM_RATE_12M, 0),
109 RATETAB_ENT(BRCM_RATE_18M, 0),
110 RATETAB_ENT(BRCM_RATE_24M, 0),
111 RATETAB_ENT(BRCM_RATE_36M, 0),
112 RATETAB_ENT(BRCM_RATE_48M, 0),
113 RATETAB_ENT(BRCM_RATE_54M, 0),
114};
115
116#define wl_a_rates (__wl_rates + 4)
117#define wl_a_rates_size 8
118#define wl_g_rates (__wl_rates + 0)
119#define wl_g_rates_size 12
120
121static struct ieee80211_channel __wl_2ghz_channels[] = {
122 CHAN2G(1, 2412, 0),
123 CHAN2G(2, 2417, 0),
124 CHAN2G(3, 2422, 0),
125 CHAN2G(4, 2427, 0),
126 CHAN2G(5, 2432, 0),
127 CHAN2G(6, 2437, 0),
128 CHAN2G(7, 2442, 0),
129 CHAN2G(8, 2447, 0),
130 CHAN2G(9, 2452, 0),
131 CHAN2G(10, 2457, 0),
132 CHAN2G(11, 2462, 0),
133 CHAN2G(12, 2467, 0),
134 CHAN2G(13, 2472, 0),
135 CHAN2G(14, 2484, 0),
136};
137
138static struct ieee80211_channel __wl_5ghz_a_channels[] = {
139 CHAN5G(34, 0), CHAN5G(36, 0),
140 CHAN5G(38, 0), CHAN5G(40, 0),
141 CHAN5G(42, 0), CHAN5G(44, 0),
142 CHAN5G(46, 0), CHAN5G(48, 0),
143 CHAN5G(52, 0), CHAN5G(56, 0),
144 CHAN5G(60, 0), CHAN5G(64, 0),
145 CHAN5G(100, 0), CHAN5G(104, 0),
146 CHAN5G(108, 0), CHAN5G(112, 0),
147 CHAN5G(116, 0), CHAN5G(120, 0),
148 CHAN5G(124, 0), CHAN5G(128, 0),
149 CHAN5G(132, 0), CHAN5G(136, 0),
150 CHAN5G(140, 0), CHAN5G(149, 0),
151 CHAN5G(153, 0), CHAN5G(157, 0),
152 CHAN5G(161, 0), CHAN5G(165, 0),
153 CHAN5G(184, 0), CHAN5G(188, 0),
154 CHAN5G(192, 0), CHAN5G(196, 0),
155 CHAN5G(200, 0), CHAN5G(204, 0),
156 CHAN5G(208, 0), CHAN5G(212, 0),
157 CHAN5G(216, 0),
158};
159
160static struct ieee80211_channel __wl_5ghz_n_channels[] = {
161 CHAN5G(32, 0), CHAN5G(34, 0),
162 CHAN5G(36, 0), CHAN5G(38, 0),
163 CHAN5G(40, 0), CHAN5G(42, 0),
164 CHAN5G(44, 0), CHAN5G(46, 0),
165 CHAN5G(48, 0), CHAN5G(50, 0),
166 CHAN5G(52, 0), CHAN5G(54, 0),
167 CHAN5G(56, 0), CHAN5G(58, 0),
168 CHAN5G(60, 0), CHAN5G(62, 0),
169 CHAN5G(64, 0), CHAN5G(66, 0),
170 CHAN5G(68, 0), CHAN5G(70, 0),
171 CHAN5G(72, 0), CHAN5G(74, 0),
172 CHAN5G(76, 0), CHAN5G(78, 0),
173 CHAN5G(80, 0), CHAN5G(82, 0),
174 CHAN5G(84, 0), CHAN5G(86, 0),
175 CHAN5G(88, 0), CHAN5G(90, 0),
176 CHAN5G(92, 0), CHAN5G(94, 0),
177 CHAN5G(96, 0), CHAN5G(98, 0),
178 CHAN5G(100, 0), CHAN5G(102, 0),
179 CHAN5G(104, 0), CHAN5G(106, 0),
180 CHAN5G(108, 0), CHAN5G(110, 0),
181 CHAN5G(112, 0), CHAN5G(114, 0),
182 CHAN5G(116, 0), CHAN5G(118, 0),
183 CHAN5G(120, 0), CHAN5G(122, 0),
184 CHAN5G(124, 0), CHAN5G(126, 0),
185 CHAN5G(128, 0), CHAN5G(130, 0),
186 CHAN5G(132, 0), CHAN5G(134, 0),
187 CHAN5G(136, 0), CHAN5G(138, 0),
188 CHAN5G(140, 0), CHAN5G(142, 0),
189 CHAN5G(144, 0), CHAN5G(145, 0),
190 CHAN5G(146, 0), CHAN5G(147, 0),
191 CHAN5G(148, 0), CHAN5G(149, 0),
192 CHAN5G(150, 0), CHAN5G(151, 0),
193 CHAN5G(152, 0), CHAN5G(153, 0),
194 CHAN5G(154, 0), CHAN5G(155, 0),
195 CHAN5G(156, 0), CHAN5G(157, 0),
196 CHAN5G(158, 0), CHAN5G(159, 0),
197 CHAN5G(160, 0), CHAN5G(161, 0),
198 CHAN5G(162, 0), CHAN5G(163, 0),
199 CHAN5G(164, 0), CHAN5G(165, 0),
200 CHAN5G(166, 0), CHAN5G(168, 0),
201 CHAN5G(170, 0), CHAN5G(172, 0),
202 CHAN5G(174, 0), CHAN5G(176, 0),
203 CHAN5G(178, 0), CHAN5G(180, 0),
204 CHAN5G(182, 0), CHAN5G(184, 0),
205 CHAN5G(186, 0), CHAN5G(188, 0),
206 CHAN5G(190, 0), CHAN5G(192, 0),
207 CHAN5G(194, 0), CHAN5G(196, 0),
208 CHAN5G(198, 0), CHAN5G(200, 0),
209 CHAN5G(202, 0), CHAN5G(204, 0),
210 CHAN5G(206, 0), CHAN5G(208, 0),
211 CHAN5G(210, 0), CHAN5G(212, 0),
212 CHAN5G(214, 0), CHAN5G(216, 0),
213 CHAN5G(218, 0), CHAN5G(220, 0),
214 CHAN5G(222, 0), CHAN5G(224, 0),
215 CHAN5G(226, 0), CHAN5G(228, 0),
216};
217
218static struct ieee80211_supported_band __wl_band_2ghz = {
219 .band = IEEE80211_BAND_2GHZ,
220 .channels = __wl_2ghz_channels,
221 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
222 .bitrates = wl_g_rates,
223 .n_bitrates = wl_g_rates_size,
224};
225
226static struct ieee80211_supported_band __wl_band_5ghz_a = {
227 .band = IEEE80211_BAND_5GHZ,
228 .channels = __wl_5ghz_a_channels,
229 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
230 .bitrates = wl_a_rates,
231 .n_bitrates = wl_a_rates_size,
232};
233
234static struct ieee80211_supported_band __wl_band_5ghz_n = {
235 .band = IEEE80211_BAND_5GHZ,
236 .channels = __wl_5ghz_n_channels,
237 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
238 .bitrates = wl_a_rates,
239 .n_bitrates = wl_a_rates_size,
240};
241
242static const u32 __wl_cipher_suites[] = {
243 WLAN_CIPHER_SUITE_WEP40,
244 WLAN_CIPHER_SUITE_WEP104,
245 WLAN_CIPHER_SUITE_TKIP,
246 WLAN_CIPHER_SUITE_CCMP,
247 WLAN_CIPHER_SUITE_AES_CMAC,
248};
249
Alwin Beukersf8e4b412011-10-12 20:51:28 +0200250/* tag_ID/length/value_buffer tuple */
251struct brcmf_tlv {
252 u8 id;
253 u8 len;
254 u8 data[1];
255};
256
Alwin Beukersef6ac172011-10-12 20:51:26 +0200257/* Quarter dBm units to mW
258 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
259 * Table is offset so the last entry is largest mW value that fits in
260 * a u16.
261 */
262
263#define QDBM_OFFSET 153 /* Offset for first entry */
264#define QDBM_TABLE_LEN 40 /* Table size */
265
266/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
267 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
268 */
269#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
270
271/* Largest mW value that will round down to the last table entry,
272 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
273 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
274 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
275 */
276#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
277
278static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
279/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
280/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
281/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
282/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
283/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
284/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
285};
286
287static u16 brcmf_qdbm_to_mw(u8 qdbm)
288{
289 uint factor = 1;
290 int idx = qdbm - QDBM_OFFSET;
291
292 if (idx >= QDBM_TABLE_LEN)
293 /* clamp to max u16 mW value */
294 return 0xFFFF;
295
296 /* scale the qdBm index up to the range of the table 0-40
297 * where an offset of 40 qdBm equals a factor of 10 mW.
298 */
299 while (idx < 0) {
300 idx += 40;
301 factor *= 10;
302 }
303
304 /* return the mW value scaled down to the correct factor of 10,
305 * adding in factor/2 to get proper rounding.
306 */
307 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
308}
309
310static u8 brcmf_mw_to_qdbm(u16 mw)
311{
312 u8 qdbm;
313 int offset;
314 uint mw_uint = mw;
315 uint boundary;
316
317 /* handle boundary case */
318 if (mw_uint <= 1)
319 return 0;
320
321 offset = QDBM_OFFSET;
322
323 /* move mw into the range of the table */
324 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
325 mw_uint *= 10;
326 offset -= 40;
327 }
328
329 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
330 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
331 nqdBm_to_mW_map[qdbm]) / 2;
332 if (mw_uint < boundary)
333 break;
334 }
335
336 qdbm += (u8) offset;
337
338 return qdbm;
339}
340
Arend van Spriel5b435de2011-10-05 13:19:03 +0200341/* function for reading/writing a single u32 from/to the dongle */
342static int
343brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par)
344{
345 int err;
346 __le32 par_le = cpu_to_le32(*par);
347
348 err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32));
349 *par = le32_to_cpu(par_le);
350
351 return err;
352}
353
354static void convert_key_from_CPU(struct brcmf_wsec_key *key,
355 struct brcmf_wsec_key_le *key_le)
356{
357 key_le->index = cpu_to_le32(key->index);
358 key_le->len = cpu_to_le32(key->len);
359 key_le->algo = cpu_to_le32(key->algo);
360 key_le->flags = cpu_to_le32(key->flags);
361 key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
362 key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
363 key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
364 memcpy(key_le->data, key->data, sizeof(key->data));
365 memcpy(key_le->ea, key->ea, sizeof(key->ea));
366}
367
368static int send_key_to_dongle(struct net_device *ndev,
369 struct brcmf_wsec_key *key)
370{
371 int err;
372 struct brcmf_wsec_key_le key_le;
373
374 convert_key_from_CPU(key, &key_le);
375 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le));
376 if (err)
377 WL_ERR("WLC_SET_KEY error (%d)\n", err);
378 return err;
379}
380
381static s32
382brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
383 enum nl80211_iftype type, u32 *flags,
384 struct vif_params *params)
385{
386 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
387 struct wireless_dev *wdev;
388 s32 infra = 0;
389 s32 err = 0;
390
391 WL_TRACE("Enter\n");
392 if (!check_sys_up(wiphy))
393 return -EIO;
394
395 switch (type) {
396 case NL80211_IFTYPE_MONITOR:
397 case NL80211_IFTYPE_WDS:
398 WL_ERR("type (%d) : currently we do not support this type\n",
399 type);
400 return -EOPNOTSUPP;
401 case NL80211_IFTYPE_ADHOC:
402 cfg_priv->conf->mode = WL_MODE_IBSS;
403 infra = 0;
404 break;
405 case NL80211_IFTYPE_STATION:
406 cfg_priv->conf->mode = WL_MODE_BSS;
407 infra = 1;
408 break;
409 default:
410 err = -EINVAL;
411 goto done;
412 }
413
414 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
415 if (err) {
416 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
417 err = -EAGAIN;
418 } else {
419 wdev = ndev->ieee80211_ptr;
420 wdev->iftype = type;
421 }
422
423 WL_INFO("IF Type = %s\n",
424 (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra");
425
426done:
427 WL_TRACE("Exit\n");
428
429 return err;
430}
431
432static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val)
433{
434 s8 buf[BRCMF_DCMD_SMLEN];
435 u32 len;
436 s32 err = 0;
437 __le32 val_le;
438
439 val_le = cpu_to_le32(val);
Alwin Beukers53a22772011-10-12 20:51:30 +0200440 len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200441 sizeof(buf));
442 BUG_ON(!len);
443
444 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
445 if (err)
446 WL_ERR("error (%d)\n", err);
447
448 return err;
449}
450
451static s32
452brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval)
453{
454 union {
455 s8 buf[BRCMF_DCMD_SMLEN];
456 __le32 val;
457 } var;
458 u32 len;
459 u32 data_null;
460 s32 err = 0;
461
462 len =
Alwin Beukers53a22772011-10-12 20:51:30 +0200463 brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
Arend van Spriel5b435de2011-10-05 13:19:03 +0200464 sizeof(var.buf));
465 BUG_ON(!len);
466 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len);
467 if (err)
468 WL_ERR("error (%d)\n", err);
469
470 *retval = le32_to_cpu(var.val);
471
472 return err;
473}
474
475static void brcmf_set_mpc(struct net_device *ndev, int mpc)
476{
477 s32 err = 0;
478 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
479
480 if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
481 err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
482 if (err) {
483 WL_ERR("fail to set mpc\n");
484 return;
485 }
486 WL_INFO("MPC : %d\n", mpc);
487 }
488}
489
490static void wl_iscan_prep(struct brcmf_scan_params_le *params_le,
491 struct brcmf_ssid *ssid)
492{
493 memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
494 params_le->bss_type = DOT11_BSSTYPE_ANY;
495 params_le->scan_type = 0;
496 params_le->channel_num = 0;
497 params_le->nprobes = cpu_to_le32(-1);
498 params_le->active_time = cpu_to_le32(-1);
499 params_le->passive_time = cpu_to_le32(-1);
500 params_le->home_time = cpu_to_le32(-1);
501 if (ssid && ssid->SSID_len)
502 memcpy(&params_le->ssid_le, ssid, sizeof(struct brcmf_ssid));
503}
504
505static s32
506brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param,
507 s32 paramlen, void *bufptr, s32 buflen)
508{
509 s32 iolen;
510
Alwin Beukers53a22772011-10-12 20:51:30 +0200511 iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200512 BUG_ON(!iolen);
513
514 return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen);
515}
516
517static s32
518brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param,
519 s32 paramlen, void *bufptr, s32 buflen)
520{
521 s32 iolen;
522
Alwin Beukers53a22772011-10-12 20:51:30 +0200523 iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200524 BUG_ON(!iolen);
525
526 return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen);
527}
528
529static s32
530brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
531 struct brcmf_ssid *ssid, u16 action)
532{
533 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
534 offsetof(struct brcmf_iscan_params_le, params_le);
535 struct brcmf_iscan_params_le *params;
536 s32 err = 0;
537
538 if (ssid && ssid->SSID_len)
539 params_size += sizeof(struct brcmf_ssid);
540 params = kzalloc(params_size, GFP_KERNEL);
541 if (!params)
542 return -ENOMEM;
543 BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
544
545 wl_iscan_prep(&params->params_le, ssid);
546
547 params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
548 params->action = cpu_to_le16(action);
549 params->scan_duration = cpu_to_le16(0);
550
551 err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size,
552 iscan->dcmd_buf, BRCMF_DCMD_SMLEN);
553 if (err) {
554 if (err == -EBUSY)
555 WL_INFO("system busy : iscan canceled\n");
556 else
557 WL_ERR("error (%d)\n", err);
558 }
559
560 kfree(params);
561 return err;
562}
563
564static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv)
565{
566 struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
567 struct net_device *ndev = cfg_to_ndev(cfg_priv);
568 struct brcmf_ssid ssid;
Arend van Spriel66831072011-10-12 20:51:19 +0200569 __le32 passive_scan;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200570 s32 err = 0;
571
572 /* Broadcast scan by default */
573 memset(&ssid, 0, sizeof(ssid));
574
575 iscan->state = WL_ISCAN_STATE_SCANING;
576
Arend van Spriel66831072011-10-12 20:51:19 +0200577 passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200578 err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN,
579 &passive_scan, sizeof(passive_scan));
580 if (err) {
581 WL_ERR("error (%d)\n", err);
582 return err;
583 }
584 brcmf_set_mpc(ndev, 0);
585 cfg_priv->iscan_kickstart = true;
586 err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
587 if (err) {
588 brcmf_set_mpc(ndev, 1);
589 cfg_priv->iscan_kickstart = false;
590 return err;
591 }
592 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
593 iscan->timer_on = 1;
594 return err;
595}
596
597static s32
598__brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
599 struct cfg80211_scan_request *request,
600 struct cfg80211_ssid *this_ssid)
601{
602 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
603 struct cfg80211_ssid *ssids;
604 struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int;
Arend van Spriel66831072011-10-12 20:51:19 +0200605 __le32 passive_scan;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200606 bool iscan_req;
607 bool spec_scan;
608 s32 err = 0;
609 u32 SSID_len;
610
611 if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
612 WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status);
613 return -EAGAIN;
614 }
615 if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) {
616 WL_ERR("Scanning being aborted : status (%lu)\n",
617 cfg_priv->status);
618 return -EAGAIN;
619 }
620 if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
621 WL_ERR("Connecting : status (%lu)\n",
622 cfg_priv->status);
623 return -EAGAIN;
624 }
625
626 iscan_req = false;
627 spec_scan = false;
628 if (request) {
629 /* scan bss */
630 ssids = request->ssids;
631 if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len))
632 iscan_req = true;
633 } else {
634 /* scan in ibss */
635 /* we don't do iscan in ibss */
636 ssids = this_ssid;
637 }
638
639 cfg_priv->scan_request = request;
640 set_bit(WL_STATUS_SCANNING, &cfg_priv->status);
641 if (iscan_req) {
642 err = brcmf_do_iscan(cfg_priv);
643 if (!err)
644 return err;
645 else
646 goto scan_out;
647 } else {
648 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
649 ssids->ssid, ssids->ssid_len);
650 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
651 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
652 sr->ssid_le.SSID_len = cpu_to_le32(0);
653 if (SSID_len) {
654 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
655 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
656 spec_scan = true;
657 } else {
658 WL_SCAN("Broadcast scan\n");
659 }
660
Arend van Spriel66831072011-10-12 20:51:19 +0200661 passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200662 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
663 &passive_scan, sizeof(passive_scan));
664 if (err) {
665 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
666 goto scan_out;
667 }
668 brcmf_set_mpc(ndev, 0);
669 err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
670 sizeof(sr->ssid_le));
671 if (err) {
672 if (err == -EBUSY)
673 WL_INFO("system busy : scan for \"%s\" "
674 "canceled\n", sr->ssid_le.SSID);
675 else
676 WL_ERR("WLC_SCAN error (%d)\n", err);
677
678 brcmf_set_mpc(ndev, 1);
679 goto scan_out;
680 }
681 }
682
683 return 0;
684
685scan_out:
686 clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
687 cfg_priv->scan_request = NULL;
688 return err;
689}
690
691static s32
692brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
693 struct cfg80211_scan_request *request)
694{
695 s32 err = 0;
696
697 WL_TRACE("Enter\n");
698
699 if (!check_sys_up(wiphy))
700 return -EIO;
701
702 err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL);
703 if (err)
704 WL_ERR("scan error (%d)\n", err);
705
706 WL_TRACE("Exit\n");
707 return err;
708}
709
710static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
711{
712 s32 err = 0;
713
714 err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold);
715 if (err)
716 WL_ERR("Error (%d)\n", err);
717
718 return err;
719}
720
721static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
722{
723 s32 err = 0;
724
725 err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold);
726 if (err)
727 WL_ERR("Error (%d)\n", err);
728
729 return err;
730}
731
732static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
733{
734 s32 err = 0;
735 u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
736
737 err = brcmf_exec_dcmd_u32(ndev, cmd, &retry);
738 if (err) {
739 WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
740 return err;
741 }
742 return err;
743}
744
745static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
746{
747 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
748 struct net_device *ndev = cfg_to_ndev(cfg_priv);
749 s32 err = 0;
750
751 WL_TRACE("Enter\n");
752 if (!check_sys_up(wiphy))
753 return -EIO;
754
755 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
756 (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) {
757 cfg_priv->conf->rts_threshold = wiphy->rts_threshold;
758 err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold);
759 if (!err)
760 goto done;
761 }
762 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
763 (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) {
764 cfg_priv->conf->frag_threshold = wiphy->frag_threshold;
765 err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold);
766 if (!err)
767 goto done;
768 }
769 if (changed & WIPHY_PARAM_RETRY_LONG
770 && (cfg_priv->conf->retry_long != wiphy->retry_long)) {
771 cfg_priv->conf->retry_long = wiphy->retry_long;
772 err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true);
773 if (!err)
774 goto done;
775 }
776 if (changed & WIPHY_PARAM_RETRY_SHORT
777 && (cfg_priv->conf->retry_short != wiphy->retry_short)) {
778 cfg_priv->conf->retry_short = wiphy->retry_short;
779 err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false);
780 if (!err)
781 goto done;
782 }
783
784done:
785 WL_TRACE("Exit\n");
786 return err;
787}
788
789static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item)
790{
791 switch (item) {
792 case WL_PROF_SEC:
793 return &cfg_priv->profile->sec;
794 case WL_PROF_BSSID:
795 return &cfg_priv->profile->bssid;
796 case WL_PROF_SSID:
797 return &cfg_priv->profile->ssid;
798 }
799 WL_ERR("invalid item (%d)\n", item);
800 return NULL;
801}
802
803static s32
804brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
805 const struct brcmf_event_msg *e, void *data, s32 item)
806{
807 s32 err = 0;
808 struct brcmf_ssid *ssid;
809
810 switch (item) {
811 case WL_PROF_SSID:
812 ssid = (struct brcmf_ssid *) data;
813 memset(cfg_priv->profile->ssid.SSID, 0,
814 sizeof(cfg_priv->profile->ssid.SSID));
815 memcpy(cfg_priv->profile->ssid.SSID,
816 ssid->SSID, ssid->SSID_len);
817 cfg_priv->profile->ssid.SSID_len = ssid->SSID_len;
818 break;
819 case WL_PROF_BSSID:
820 if (data)
821 memcpy(cfg_priv->profile->bssid, data, ETH_ALEN);
822 else
823 memset(cfg_priv->profile->bssid, 0, ETH_ALEN);
824 break;
825 case WL_PROF_SEC:
826 memcpy(&cfg_priv->profile->sec, data,
827 sizeof(cfg_priv->profile->sec));
828 break;
829 case WL_PROF_BEACONINT:
830 cfg_priv->profile->beacon_interval = *(u16 *)data;
831 break;
832 case WL_PROF_DTIMPERIOD:
833 cfg_priv->profile->dtim_period = *(u8 *)data;
834 break;
835 default:
836 WL_ERR("unsupported item (%d)\n", item);
837 err = -EOPNOTSUPP;
838 break;
839 }
840
841 return err;
842}
843
844static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
845{
846 memset(prof, 0, sizeof(*prof));
847}
848
849static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
850 size_t *join_params_size)
851{
852 u16 chanspec = 0;
853
854 if (ch != 0) {
855 if (ch <= CH_MAX_2G_CHANNEL)
856 chanspec |= WL_CHANSPEC_BAND_2G;
857 else
858 chanspec |= WL_CHANSPEC_BAND_5G;
859
860 chanspec |= WL_CHANSPEC_BW_20;
861 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
862
863 *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
864 sizeof(u16);
865
866 chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
867 join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
868 join_params->params_le.chanspec_num = cpu_to_le32(1);
869
870 WL_CONN("join_params->params.chanspec_list[0]= %#X,"
871 "channel %d, chanspec %#X\n",
872 chanspec, ch, chanspec);
873 }
874}
875
876static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv)
877{
878 struct net_device *ndev = NULL;
879 s32 err = 0;
880
881 WL_TRACE("Enter\n");
882
883 if (cfg_priv->link_up) {
884 ndev = cfg_to_ndev(cfg_priv);
885 WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
886 err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0);
887 if (err)
888 WL_ERR("WLC_DISASSOC failed (%d)\n", err);
889 cfg_priv->link_up = false;
890 }
891 WL_TRACE("Exit\n");
892}
893
894static s32
895brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
896 struct cfg80211_ibss_params *params)
897{
898 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
899 struct brcmf_join_params join_params;
900 size_t join_params_size = 0;
901 s32 err = 0;
902 s32 wsec = 0;
903 s32 bcnprd;
904 struct brcmf_ssid ssid;
905
906 WL_TRACE("Enter\n");
907 if (!check_sys_up(wiphy))
908 return -EIO;
909
910 if (params->ssid)
911 WL_CONN("SSID: %s\n", params->ssid);
912 else {
913 WL_CONN("SSID: NULL, Not supported\n");
914 return -EOPNOTSUPP;
915 }
916
917 set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
918
919 if (params->bssid)
920 WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n",
921 params->bssid[0], params->bssid[1], params->bssid[2],
922 params->bssid[3], params->bssid[4], params->bssid[5]);
923 else
924 WL_CONN("No BSSID specified\n");
925
926 if (params->channel)
927 WL_CONN("channel: %d\n", params->channel->center_freq);
928 else
929 WL_CONN("no channel specified\n");
930
931 if (params->channel_fixed)
932 WL_CONN("fixed channel required\n");
933 else
934 WL_CONN("no fixed channel required\n");
935
936 if (params->ie && params->ie_len)
937 WL_CONN("ie len: %d\n", params->ie_len);
938 else
939 WL_CONN("no ie specified\n");
940
941 if (params->beacon_interval)
942 WL_CONN("beacon interval: %d\n", params->beacon_interval);
943 else
944 WL_CONN("no beacon interval specified\n");
945
946 if (params->basic_rates)
947 WL_CONN("basic rates: %08X\n", params->basic_rates);
948 else
949 WL_CONN("no basic rates specified\n");
950
951 if (params->privacy)
952 WL_CONN("privacy required\n");
953 else
954 WL_CONN("no privacy required\n");
955
956 /* Configure Privacy for starter */
957 if (params->privacy)
958 wsec |= WEP_ENABLED;
959
960 err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
961 if (err) {
962 WL_ERR("wsec failed (%d)\n", err);
963 goto done;
964 }
965
966 /* Configure Beacon Interval for starter */
967 if (params->beacon_interval)
968 bcnprd = params->beacon_interval;
969 else
970 bcnprd = 100;
971
972 err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd);
973 if (err) {
974 WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
975 goto done;
976 }
977
978 /* Configure required join parameter */
979 memset(&join_params, 0, sizeof(struct brcmf_join_params));
980
981 /* SSID */
982 ssid.SSID_len = min_t(u32, params->ssid_len, 32);
983 memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
984 memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len);
985 join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
986 join_params_size = sizeof(join_params.ssid_le);
987 brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
988
989 /* BSSID */
990 if (params->bssid) {
991 memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
992 join_params_size = sizeof(join_params.ssid_le) +
993 BRCMF_ASSOC_PARAMS_FIXED_SIZE;
994 } else {
995 memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
996 }
997
998 brcmf_update_prof(cfg_priv, NULL,
999 &join_params.params_le.bssid, WL_PROF_BSSID);
1000
1001 /* Channel */
1002 if (params->channel) {
1003 u32 target_channel;
1004
1005 cfg_priv->channel =
1006 ieee80211_frequency_to_channel(
1007 params->channel->center_freq);
1008 if (params->channel_fixed) {
1009 /* adding chanspec */
1010 brcmf_ch_to_chanspec(cfg_priv->channel,
1011 &join_params, &join_params_size);
1012 }
1013
1014 /* set channel for starter */
1015 target_channel = cfg_priv->channel;
1016 err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL,
1017 &target_channel);
1018 if (err) {
1019 WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
1020 goto done;
1021 }
1022 } else
1023 cfg_priv->channel = 0;
1024
1025 cfg_priv->ibss_starter = false;
1026
1027
1028 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
1029 &join_params, join_params_size);
1030 if (err) {
1031 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1032 goto done;
1033 }
1034
1035done:
1036 if (err)
1037 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
1038 WL_TRACE("Exit\n");
1039 return err;
1040}
1041
1042static s32
1043brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1044{
1045 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1046 s32 err = 0;
1047
1048 WL_TRACE("Enter\n");
1049 if (!check_sys_up(wiphy))
1050 return -EIO;
1051
1052 brcmf_link_down(cfg_priv);
1053
1054 WL_TRACE("Exit\n");
1055
1056 return err;
1057}
1058
1059static s32 brcmf_set_wpa_version(struct net_device *ndev,
1060 struct cfg80211_connect_params *sme)
1061{
1062 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1063 struct brcmf_cfg80211_security *sec;
1064 s32 val = 0;
1065 s32 err = 0;
1066
1067 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1068 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1069 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1070 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1071 else
1072 val = WPA_AUTH_DISABLED;
1073 WL_CONN("setting wpa_auth to 0x%0x\n", val);
1074 err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
1075 if (err) {
1076 WL_ERR("set wpa_auth failed (%d)\n", err);
1077 return err;
1078 }
1079 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1080 sec->wpa_versions = sme->crypto.wpa_versions;
1081 return err;
1082}
1083
1084static s32 brcmf_set_auth_type(struct net_device *ndev,
1085 struct cfg80211_connect_params *sme)
1086{
1087 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1088 struct brcmf_cfg80211_security *sec;
1089 s32 val = 0;
1090 s32 err = 0;
1091
1092 switch (sme->auth_type) {
1093 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1094 val = 0;
1095 WL_CONN("open system\n");
1096 break;
1097 case NL80211_AUTHTYPE_SHARED_KEY:
1098 val = 1;
1099 WL_CONN("shared key\n");
1100 break;
1101 case NL80211_AUTHTYPE_AUTOMATIC:
1102 val = 2;
1103 WL_CONN("automatic\n");
1104 break;
1105 case NL80211_AUTHTYPE_NETWORK_EAP:
1106 WL_CONN("network eap\n");
1107 default:
1108 val = 2;
1109 WL_ERR("invalid auth type (%d)\n", sme->auth_type);
1110 break;
1111 }
1112
1113 err = brcmf_dev_intvar_set(ndev, "auth", val);
1114 if (err) {
1115 WL_ERR("set auth failed (%d)\n", err);
1116 return err;
1117 }
1118 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1119 sec->auth_type = sme->auth_type;
1120 return err;
1121}
1122
1123static s32
1124brcmf_set_set_cipher(struct net_device *ndev,
1125 struct cfg80211_connect_params *sme)
1126{
1127 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1128 struct brcmf_cfg80211_security *sec;
1129 s32 pval = 0;
1130 s32 gval = 0;
1131 s32 err = 0;
1132
1133 if (sme->crypto.n_ciphers_pairwise) {
1134 switch (sme->crypto.ciphers_pairwise[0]) {
1135 case WLAN_CIPHER_SUITE_WEP40:
1136 case WLAN_CIPHER_SUITE_WEP104:
1137 pval = WEP_ENABLED;
1138 break;
1139 case WLAN_CIPHER_SUITE_TKIP:
1140 pval = TKIP_ENABLED;
1141 break;
1142 case WLAN_CIPHER_SUITE_CCMP:
1143 pval = AES_ENABLED;
1144 break;
1145 case WLAN_CIPHER_SUITE_AES_CMAC:
1146 pval = AES_ENABLED;
1147 break;
1148 default:
1149 WL_ERR("invalid cipher pairwise (%d)\n",
1150 sme->crypto.ciphers_pairwise[0]);
1151 return -EINVAL;
1152 }
1153 }
1154 if (sme->crypto.cipher_group) {
1155 switch (sme->crypto.cipher_group) {
1156 case WLAN_CIPHER_SUITE_WEP40:
1157 case WLAN_CIPHER_SUITE_WEP104:
1158 gval = WEP_ENABLED;
1159 break;
1160 case WLAN_CIPHER_SUITE_TKIP:
1161 gval = TKIP_ENABLED;
1162 break;
1163 case WLAN_CIPHER_SUITE_CCMP:
1164 gval = AES_ENABLED;
1165 break;
1166 case WLAN_CIPHER_SUITE_AES_CMAC:
1167 gval = AES_ENABLED;
1168 break;
1169 default:
1170 WL_ERR("invalid cipher group (%d)\n",
1171 sme->crypto.cipher_group);
1172 return -EINVAL;
1173 }
1174 }
1175
1176 WL_CONN("pval (%d) gval (%d)\n", pval, gval);
1177 err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval);
1178 if (err) {
1179 WL_ERR("error (%d)\n", err);
1180 return err;
1181 }
1182
1183 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1184 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1185 sec->cipher_group = sme->crypto.cipher_group;
1186
1187 return err;
1188}
1189
1190static s32
1191brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
1192{
1193 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1194 struct brcmf_cfg80211_security *sec;
1195 s32 val = 0;
1196 s32 err = 0;
1197
1198 if (sme->crypto.n_akm_suites) {
1199 err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val);
1200 if (err) {
1201 WL_ERR("could not get wpa_auth (%d)\n", err);
1202 return err;
1203 }
1204 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1205 switch (sme->crypto.akm_suites[0]) {
1206 case WLAN_AKM_SUITE_8021X:
1207 val = WPA_AUTH_UNSPECIFIED;
1208 break;
1209 case WLAN_AKM_SUITE_PSK:
1210 val = WPA_AUTH_PSK;
1211 break;
1212 default:
1213 WL_ERR("invalid cipher group (%d)\n",
1214 sme->crypto.cipher_group);
1215 return -EINVAL;
1216 }
1217 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1218 switch (sme->crypto.akm_suites[0]) {
1219 case WLAN_AKM_SUITE_8021X:
1220 val = WPA2_AUTH_UNSPECIFIED;
1221 break;
1222 case WLAN_AKM_SUITE_PSK:
1223 val = WPA2_AUTH_PSK;
1224 break;
1225 default:
1226 WL_ERR("invalid cipher group (%d)\n",
1227 sme->crypto.cipher_group);
1228 return -EINVAL;
1229 }
1230 }
1231
1232 WL_CONN("setting wpa_auth to %d\n", val);
1233 err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
1234 if (err) {
1235 WL_ERR("could not set wpa_auth (%d)\n", err);
1236 return err;
1237 }
1238 }
1239 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1240 sec->wpa_auth = sme->crypto.akm_suites[0];
1241
1242 return err;
1243}
1244
1245static s32
Roland Vossena718e2f2011-10-12 20:51:24 +02001246brcmf_set_wep_sharedkey(struct net_device *ndev,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001247 struct cfg80211_connect_params *sme)
1248{
1249 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
1250 struct brcmf_cfg80211_security *sec;
1251 struct brcmf_wsec_key key;
1252 s32 val;
1253 s32 err = 0;
1254
1255 WL_CONN("key len (%d)\n", sme->key_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001256
Roland Vossena718e2f2011-10-12 20:51:24 +02001257 if (sme->key_len == 0)
1258 return 0;
1259
1260 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1261 WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n",
1262 sec->wpa_versions, sec->cipher_pairwise);
1263
1264 if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
1265 return 0;
1266
1267 if (sec->cipher_pairwise &
1268 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) {
1269 memset(&key, 0, sizeof(key));
1270 key.len = (u32) sme->key_len;
1271 key.index = (u32) sme->key_idx;
1272 if (key.len > sizeof(key.data)) {
1273 WL_ERR("Too long key length (%u)\n", key.len);
1274 return -EINVAL;
1275 }
1276 memcpy(key.data, sme->key, key.len);
1277 key.flags = BRCMF_PRIMARY_KEY;
1278 switch (sec->cipher_pairwise) {
1279 case WLAN_CIPHER_SUITE_WEP40:
1280 key.algo = CRYPTO_ALGO_WEP1;
1281 break;
1282 case WLAN_CIPHER_SUITE_WEP104:
1283 key.algo = CRYPTO_ALGO_WEP128;
1284 break;
1285 default:
1286 WL_ERR("Invalid algorithm (%d)\n",
1287 sme->crypto.ciphers_pairwise[0]);
1288 return -EINVAL;
1289 }
1290 /* Set the new key/index */
1291 WL_CONN("key length (%d) key index (%d) algo (%d)\n",
1292 key.len, key.index, key.algo);
1293 WL_CONN("key \"%s\"\n", key.data);
1294 err = send_key_to_dongle(ndev, &key);
1295 if (err)
1296 return err;
1297
1298 if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
1299 WL_CONN("set auth_type to shared key\n");
1300 val = 1; /* shared key */
1301 err = brcmf_dev_intvar_set(ndev, "auth", val);
1302 if (err) {
1303 WL_ERR("set auth failed (%d)\n", err);
1304 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001305 }
1306 }
1307 }
1308 return err;
1309}
1310
1311static s32
1312brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1313 struct cfg80211_connect_params *sme)
1314{
1315 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1316 struct ieee80211_channel *chan = sme->channel;
1317 struct brcmf_join_params join_params;
1318 size_t join_params_size;
1319 struct brcmf_ssid ssid;
1320
1321 s32 err = 0;
1322
1323 WL_TRACE("Enter\n");
1324 if (!check_sys_up(wiphy))
1325 return -EIO;
1326
1327 if (!sme->ssid) {
1328 WL_ERR("Invalid ssid\n");
1329 return -EOPNOTSUPP;
1330 }
1331
1332 set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
1333
1334 if (chan) {
1335 cfg_priv->channel =
1336 ieee80211_frequency_to_channel(chan->center_freq);
1337 WL_CONN("channel (%d), center_req (%d)\n",
1338 cfg_priv->channel, chan->center_freq);
1339 } else
1340 cfg_priv->channel = 0;
1341
1342 WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1343
1344 err = brcmf_set_wpa_version(ndev, sme);
1345 if (err) {
1346 WL_ERR("wl_set_wpa_version failed (%d)\n", err);
1347 goto done;
1348 }
1349
1350 err = brcmf_set_auth_type(ndev, sme);
1351 if (err) {
1352 WL_ERR("wl_set_auth_type failed (%d)\n", err);
1353 goto done;
1354 }
1355
1356 err = brcmf_set_set_cipher(ndev, sme);
1357 if (err) {
1358 WL_ERR("wl_set_set_cipher failed (%d)\n", err);
1359 goto done;
1360 }
1361
1362 err = brcmf_set_key_mgmt(ndev, sme);
1363 if (err) {
1364 WL_ERR("wl_set_key_mgmt failed (%d)\n", err);
1365 goto done;
1366 }
1367
Roland Vossena718e2f2011-10-12 20:51:24 +02001368 err = brcmf_set_wep_sharedkey(ndev, sme);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001369 if (err) {
Roland Vossena718e2f2011-10-12 20:51:24 +02001370 WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001371 goto done;
1372 }
1373
1374 memset(&join_params, 0, sizeof(join_params));
1375 join_params_size = sizeof(join_params.ssid_le);
1376
1377 ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len);
1378 memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len);
1379 memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len);
1380 join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
1381 brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
1382
1383 memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
1384
1385 if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
1386 WL_CONN("ssid \"%s\", len (%d)\n",
1387 ssid.SSID, ssid.SSID_len);
1388
1389 brcmf_ch_to_chanspec(cfg_priv->channel,
1390 &join_params, &join_params_size);
1391 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
1392 &join_params, join_params_size);
1393 if (err)
1394 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1395
1396done:
1397 if (err)
1398 clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
1399 WL_TRACE("Exit\n");
1400 return err;
1401}
1402
1403static s32
1404brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
1405 u16 reason_code)
1406{
1407 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1408 struct brcmf_scb_val_le scbval;
1409 s32 err = 0;
1410
1411 WL_TRACE("Enter. Reason code = %d\n", reason_code);
1412 if (!check_sys_up(wiphy))
1413 return -EIO;
1414
1415 clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
1416
1417 memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN);
1418 scbval.val = cpu_to_le32(reason_code);
1419 err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval,
1420 sizeof(struct brcmf_scb_val_le));
1421 if (err)
1422 WL_ERR("error (%d)\n", err);
1423
1424 cfg_priv->link_up = false;
1425
1426 WL_TRACE("Exit\n");
1427 return err;
1428}
1429
1430static s32
1431brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
1432 enum nl80211_tx_power_setting type, s32 dbm)
1433{
1434
1435 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1436 struct net_device *ndev = cfg_to_ndev(cfg_priv);
1437 u16 txpwrmw;
1438 s32 err = 0;
1439 s32 disable = 0;
1440
1441 WL_TRACE("Enter\n");
1442 if (!check_sys_up(wiphy))
1443 return -EIO;
1444
1445 switch (type) {
1446 case NL80211_TX_POWER_AUTOMATIC:
1447 break;
1448 case NL80211_TX_POWER_LIMITED:
1449 if (dbm < 0) {
1450 WL_ERR("TX_POWER_LIMITED - dbm is negative\n");
1451 err = -EINVAL;
1452 goto done;
1453 }
1454 break;
1455 case NL80211_TX_POWER_FIXED:
1456 if (dbm < 0) {
1457 WL_ERR("TX_POWER_FIXED - dbm is negative\n");
1458 err = -EINVAL;
1459 goto done;
1460 }
1461 break;
1462 }
1463 /* Make sure radio is off or on as far as software is concerned */
1464 disable = WL_RADIO_SW_DISABLE << 16;
1465 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable);
1466 if (err)
1467 WL_ERR("WLC_SET_RADIO error (%d)\n", err);
1468
1469 if (dbm > 0xffff)
1470 txpwrmw = 0xffff;
1471 else
1472 txpwrmw = (u16) dbm;
1473 err = brcmf_dev_intvar_set(ndev, "qtxpower",
Alwin Beukersef6ac172011-10-12 20:51:26 +02001474 (s32) (brcmf_mw_to_qdbm(txpwrmw)));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001475 if (err)
1476 WL_ERR("qtxpower error (%d)\n", err);
1477 cfg_priv->conf->tx_power = dbm;
1478
1479done:
1480 WL_TRACE("Exit\n");
1481 return err;
1482}
1483
1484static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
1485{
1486 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1487 struct net_device *ndev = cfg_to_ndev(cfg_priv);
1488 s32 txpwrdbm;
1489 u8 result;
1490 s32 err = 0;
1491
1492 WL_TRACE("Enter\n");
1493 if (!check_sys_up(wiphy))
1494 return -EIO;
1495
1496 err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
1497 if (err) {
1498 WL_ERR("error (%d)\n", err);
1499 goto done;
1500 }
1501
1502 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
Alwin Beukersef6ac172011-10-12 20:51:26 +02001503 *dbm = (s32) brcmf_qdbm_to_mw(result);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001504
1505done:
1506 WL_TRACE("Exit\n");
1507 return err;
1508}
1509
1510static s32
1511brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
1512 u8 key_idx, bool unicast, bool multicast)
1513{
1514 u32 index;
1515 u32 wsec;
1516 s32 err = 0;
1517
1518 WL_TRACE("Enter\n");
1519 WL_CONN("key index (%d)\n", key_idx);
1520 if (!check_sys_up(wiphy))
1521 return -EIO;
1522
1523 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
1524 if (err) {
1525 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1526 goto done;
1527 }
1528
1529 if (wsec & WEP_ENABLED) {
1530 /* Just select a new current key */
1531 index = key_idx;
1532 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY,
1533 &index);
1534 if (err)
1535 WL_ERR("error (%d)\n", err);
1536 }
1537done:
1538 WL_TRACE("Exit\n");
1539 return err;
1540}
1541
1542static s32
1543brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
1544 u8 key_idx, const u8 *mac_addr, struct key_params *params)
1545{
1546 struct brcmf_wsec_key key;
1547 struct brcmf_wsec_key_le key_le;
1548 s32 err = 0;
1549
1550 memset(&key, 0, sizeof(key));
1551 key.index = (u32) key_idx;
1552 /* Instead of bcast for ea address for default wep keys,
1553 driver needs it to be Null */
1554 if (!is_multicast_ether_addr(mac_addr))
1555 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
1556 key.len = (u32) params->key_len;
1557 /* check for key index change */
1558 if (key.len == 0) {
1559 /* key delete */
1560 err = send_key_to_dongle(ndev, &key);
1561 if (err)
1562 return err;
1563 } else {
1564 if (key.len > sizeof(key.data)) {
1565 WL_ERR("Invalid key length (%d)\n", key.len);
1566 return -EINVAL;
1567 }
1568
1569 WL_CONN("Setting the key index %d\n", key.index);
1570 memcpy(key.data, params->key, key.len);
1571
1572 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
1573 u8 keybuf[8];
1574 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1575 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1576 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1577 }
1578
1579 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1580 if (params->seq && params->seq_len == 6) {
1581 /* rx iv */
1582 u8 *ivptr;
1583 ivptr = (u8 *) params->seq;
1584 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1585 (ivptr[3] << 8) | ivptr[2];
1586 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1587 key.iv_initialized = true;
1588 }
1589
1590 switch (params->cipher) {
1591 case WLAN_CIPHER_SUITE_WEP40:
1592 key.algo = CRYPTO_ALGO_WEP1;
1593 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1594 break;
1595 case WLAN_CIPHER_SUITE_WEP104:
1596 key.algo = CRYPTO_ALGO_WEP128;
1597 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1598 break;
1599 case WLAN_CIPHER_SUITE_TKIP:
1600 key.algo = CRYPTO_ALGO_TKIP;
1601 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1602 break;
1603 case WLAN_CIPHER_SUITE_AES_CMAC:
1604 key.algo = CRYPTO_ALGO_AES_CCM;
1605 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1606 break;
1607 case WLAN_CIPHER_SUITE_CCMP:
1608 key.algo = CRYPTO_ALGO_AES_CCM;
1609 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
1610 break;
1611 default:
1612 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1613 return -EINVAL;
1614 }
1615 convert_key_from_CPU(&key, &key_le);
1616
1617 brcmf_netdev_wait_pend8021x(ndev);
1618 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le,
1619 sizeof(key_le));
1620 if (err) {
1621 WL_ERR("WLC_SET_KEY error (%d)\n", err);
1622 return err;
1623 }
1624 }
1625 return err;
1626}
1627
1628static s32
1629brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
1630 u8 key_idx, bool pairwise, const u8 *mac_addr,
1631 struct key_params *params)
1632{
1633 struct brcmf_wsec_key key;
1634 s32 val;
1635 s32 wsec;
1636 s32 err = 0;
1637 u8 keybuf[8];
1638
1639 WL_TRACE("Enter\n");
1640 WL_CONN("key index (%d)\n", key_idx);
1641 if (!check_sys_up(wiphy))
1642 return -EIO;
1643
1644 if (mac_addr) {
1645 WL_TRACE("Exit");
1646 return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
1647 }
1648 memset(&key, 0, sizeof(key));
1649
1650 key.len = (u32) params->key_len;
1651 key.index = (u32) key_idx;
1652
1653 if (key.len > sizeof(key.data)) {
1654 WL_ERR("Too long key length (%u)\n", key.len);
1655 err = -EINVAL;
1656 goto done;
1657 }
1658 memcpy(key.data, params->key, key.len);
1659
1660 key.flags = BRCMF_PRIMARY_KEY;
1661 switch (params->cipher) {
1662 case WLAN_CIPHER_SUITE_WEP40:
1663 key.algo = CRYPTO_ALGO_WEP1;
1664 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1665 break;
1666 case WLAN_CIPHER_SUITE_WEP104:
1667 key.algo = CRYPTO_ALGO_WEP128;
1668 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1669 break;
1670 case WLAN_CIPHER_SUITE_TKIP:
1671 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1672 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1673 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1674 key.algo = CRYPTO_ALGO_TKIP;
1675 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1676 break;
1677 case WLAN_CIPHER_SUITE_AES_CMAC:
1678 key.algo = CRYPTO_ALGO_AES_CCM;
1679 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1680 break;
1681 case WLAN_CIPHER_SUITE_CCMP:
1682 key.algo = CRYPTO_ALGO_AES_CCM;
1683 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
1684 break;
1685 default:
1686 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1687 err = -EINVAL;
1688 goto done;
1689 }
1690
1691 err = send_key_to_dongle(ndev, &key); /* Set the new key/index */
1692 if (err)
1693 goto done;
1694
1695 val = WEP_ENABLED;
1696 err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
1697 if (err) {
1698 WL_ERR("get wsec error (%d)\n", err);
1699 goto done;
1700 }
1701 wsec &= ~(WEP_ENABLED);
1702 wsec |= val;
1703 err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
1704 if (err) {
1705 WL_ERR("set wsec error (%d)\n", err);
1706 goto done;
1707 }
1708
1709 val = 1; /* assume shared key. otherwise 0 */
1710 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
1711 if (err)
1712 WL_ERR("WLC_SET_AUTH error (%d)\n", err);
1713done:
1714 WL_TRACE("Exit\n");
1715 return err;
1716}
1717
1718static s32
1719brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
1720 u8 key_idx, bool pairwise, const u8 *mac_addr)
1721{
1722 struct brcmf_wsec_key key;
1723 s32 err = 0;
1724 s32 val;
1725 s32 wsec;
1726
1727 WL_TRACE("Enter\n");
1728 if (!check_sys_up(wiphy))
1729 return -EIO;
1730
1731 memset(&key, 0, sizeof(key));
1732
1733 key.index = (u32) key_idx;
1734 key.flags = BRCMF_PRIMARY_KEY;
1735 key.algo = CRYPTO_ALGO_OFF;
1736
1737 WL_CONN("key index (%d)\n", key_idx);
1738
1739 /* Set the new key/index */
1740 err = send_key_to_dongle(ndev, &key);
1741 if (err) {
1742 if (err == -EINVAL) {
1743 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
1744 /* we ignore this key index in this case */
1745 WL_ERR("invalid key index (%d)\n", key_idx);
1746 }
1747 /* Ignore this error, may happen during DISASSOC */
1748 err = -EAGAIN;
1749 goto done;
1750 }
1751
1752 val = 0;
1753 err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
1754 if (err) {
1755 WL_ERR("get wsec error (%d)\n", err);
1756 /* Ignore this error, may happen during DISASSOC */
1757 err = -EAGAIN;
1758 goto done;
1759 }
1760 wsec &= ~(WEP_ENABLED);
1761 wsec |= val;
1762 err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
1763 if (err) {
1764 WL_ERR("set wsec error (%d)\n", err);
1765 /* Ignore this error, may happen during DISASSOC */
1766 err = -EAGAIN;
1767 goto done;
1768 }
1769
1770 val = 0; /* assume open key. otherwise 1 */
1771 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
1772 if (err) {
1773 WL_ERR("WLC_SET_AUTH error (%d)\n", err);
1774 /* Ignore this error, may happen during DISASSOC */
1775 err = -EAGAIN;
1776 }
1777done:
1778 WL_TRACE("Exit\n");
1779 return err;
1780}
1781
1782static s32
1783brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1784 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
1785 void (*callback) (void *cookie, struct key_params * params))
1786{
1787 struct key_params params;
1788 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1789 struct brcmf_cfg80211_security *sec;
1790 s32 wsec;
1791 s32 err = 0;
1792
1793 WL_TRACE("Enter\n");
1794 WL_CONN("key index (%d)\n", key_idx);
1795 if (!check_sys_up(wiphy))
1796 return -EIO;
1797
1798 memset(&params, 0, sizeof(params));
1799
1800 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
1801 if (err) {
1802 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1803 /* Ignore this error, may happen during DISASSOC */
1804 err = -EAGAIN;
1805 goto done;
1806 }
1807 switch (wsec) {
1808 case WEP_ENABLED:
1809 sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
1810 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1811 params.cipher = WLAN_CIPHER_SUITE_WEP40;
1812 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
1813 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1814 params.cipher = WLAN_CIPHER_SUITE_WEP104;
1815 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
1816 }
1817 break;
1818 case TKIP_ENABLED:
1819 params.cipher = WLAN_CIPHER_SUITE_TKIP;
1820 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
1821 break;
1822 case AES_ENABLED:
1823 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
1824 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
1825 break;
1826 default:
1827 WL_ERR("Invalid algo (0x%x)\n", wsec);
1828 err = -EINVAL;
1829 goto done;
1830 }
1831 callback(cookie, &params);
1832
1833done:
1834 WL_TRACE("Exit\n");
1835 return err;
1836}
1837
1838static s32
1839brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
1840 struct net_device *ndev, u8 key_idx)
1841{
1842 WL_INFO("Not supported\n");
1843
1844 return -EOPNOTSUPP;
1845}
1846
1847static s32
1848brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
1849 u8 *mac, struct station_info *sinfo)
1850{
1851 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1852 struct brcmf_scb_val_le scb_val;
1853 int rssi;
1854 s32 rate;
1855 s32 err = 0;
1856 u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID);
1857
1858 WL_TRACE("Enter\n");
1859 if (!check_sys_up(wiphy))
1860 return -EIO;
1861
1862 if (memcmp(mac, bssid, ETH_ALEN)) {
1863 WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X"
1864 "wl_bssid-%X:%X:%X:%X:%X:%X\n",
1865 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
1866 bssid[0], bssid[1], bssid[2], bssid[3],
1867 bssid[4], bssid[5]);
1868 err = -ENOENT;
1869 goto done;
1870 }
1871
1872 /* Report the current tx rate */
1873 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate);
1874 if (err) {
1875 WL_ERR("Could not get rate (%d)\n", err);
1876 } else {
1877 sinfo->filled |= STATION_INFO_TX_BITRATE;
1878 sinfo->txrate.legacy = rate * 5;
1879 WL_CONN("Rate %d Mbps\n", rate / 2);
1880 }
1881
1882 if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
1883 scb_val.val = cpu_to_le32(0);
1884 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
1885 sizeof(struct brcmf_scb_val_le));
1886 if (err)
1887 WL_ERR("Could not get rssi (%d)\n", err);
1888
1889 rssi = le32_to_cpu(scb_val.val);
1890 sinfo->filled |= STATION_INFO_SIGNAL;
1891 sinfo->signal = rssi;
1892 WL_CONN("RSSI %d dBm\n", rssi);
1893 }
1894
1895done:
1896 WL_TRACE("Exit\n");
1897 return err;
1898}
1899
1900static s32
1901brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
1902 bool enabled, s32 timeout)
1903{
1904 s32 pm;
1905 s32 err = 0;
1906 struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
1907
1908 WL_TRACE("Enter\n");
1909
1910 /*
1911 * Powersave enable/disable request is coming from the
1912 * cfg80211 even before the interface is up. In that
1913 * scenario, driver will be storing the power save
1914 * preference in cfg_priv struct to apply this to
1915 * FW later while initializing the dongle
1916 */
1917 cfg_priv->pwr_save = enabled;
1918 if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
1919
1920 WL_INFO("Device is not ready,"
1921 "storing the value in cfg_priv struct\n");
1922 goto done;
1923 }
1924
1925 pm = enabled ? PM_FAST : PM_OFF;
1926 WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
1927
1928 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm);
1929 if (err) {
1930 if (err == -ENODEV)
1931 WL_ERR("net_device is not ready yet\n");
1932 else
1933 WL_ERR("error (%d)\n", err);
1934 }
1935done:
1936 WL_TRACE("Exit\n");
1937 return err;
1938}
1939
1940static s32
1941brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
1942 const u8 *addr,
1943 const struct cfg80211_bitrate_mask *mask)
1944{
1945 struct brcm_rateset_le rateset_le;
1946 s32 rate;
1947 s32 val;
1948 s32 err_bg;
1949 s32 err_a;
1950 u32 legacy;
1951 s32 err = 0;
1952
1953 WL_TRACE("Enter\n");
1954 if (!check_sys_up(wiphy))
1955 return -EIO;
1956
1957 /* addr param is always NULL. ignore it */
1958 /* Get current rateset */
1959 err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le,
1960 sizeof(rateset_le));
1961 if (err) {
1962 WL_ERR("could not get current rateset (%d)\n", err);
1963 goto done;
1964 }
1965
1966 legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
1967 if (!legacy)
1968 legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
1969 0xFFFF);
1970
1971 val = wl_g_rates[legacy - 1].bitrate * 100000;
1972
1973 if (val < le32_to_cpu(rateset_le.count))
1974 /* Select rate by rateset index */
1975 rate = rateset_le.rates[val] & 0x7f;
1976 else
1977 /* Specified rate in bps */
1978 rate = val / 500000;
1979
1980 WL_CONN("rate %d mbps\n", rate / 2);
1981
1982 /*
1983 *
1984 * Set rate override,
1985 * Since the is a/b/g-blind, both a/bg_rate are enforced.
1986 */
1987 err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate);
1988 err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate);
1989 if (err_bg && err_a) {
1990 WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
1991 err = err_bg | err_a;
1992 }
1993
1994done:
1995 WL_TRACE("Exit\n");
1996 return err;
1997}
1998
1999static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
Roland Vossend34bf642011-10-18 14:03:01 +02002000 struct brcmf_bss_info_le *bi)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002001{
2002 struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
2003 struct ieee80211_channel *notify_channel;
2004 struct cfg80211_bss *bss;
2005 struct ieee80211_supported_band *band;
2006 s32 err = 0;
2007 u16 channel;
2008 u32 freq;
2009 u64 notify_timestamp;
2010 u16 notify_capability;
2011 u16 notify_interval;
2012 u8 *notify_ie;
2013 size_t notify_ielen;
2014 s32 notify_signal;
2015
2016 if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
2017 WL_ERR("Bss info is larger than buffer. Discarding\n");
2018 return 0;
2019 }
2020
2021 channel = bi->ctl_ch ? bi->ctl_ch :
2022 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2023
2024 if (channel <= CH_MAX_2G_CHANNEL)
2025 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2026 else
2027 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2028
2029 freq = ieee80211_channel_to_frequency(channel, band->band);
2030 notify_channel = ieee80211_get_channel(wiphy, freq);
2031
2032 notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
2033 notify_capability = le16_to_cpu(bi->capability);
2034 notify_interval = le16_to_cpu(bi->beacon_period);
2035 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2036 notify_ielen = le32_to_cpu(bi->ie_length);
2037 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2038
2039 WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
2040 bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
2041 bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
2042 WL_CONN("Channel: %d(%d)\n", channel, freq);
2043 WL_CONN("Capability: %X\n", notify_capability);
2044 WL_CONN("Beacon interval: %d\n", notify_interval);
2045 WL_CONN("Signal: %d\n", notify_signal);
2046 WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
2047
2048 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
2049 notify_timestamp, notify_capability, notify_interval, notify_ie,
2050 notify_ielen, notify_signal, GFP_KERNEL);
2051
2052 if (!bss) {
2053 WL_ERR("cfg80211_inform_bss_frame error\n");
2054 return -EINVAL;
2055 }
2056
2057 return err;
2058}
2059
Roland Vossen6f09be02011-10-18 14:03:02 +02002060static struct brcmf_bss_info_le *
2061next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
2062{
2063 if (bss == NULL)
2064 return list->bss_info_le;
2065 return (struct brcmf_bss_info_le *)((unsigned long)bss +
2066 le32_to_cpu(bss->length));
2067}
2068
Arend van Spriel5b435de2011-10-05 13:19:03 +02002069static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
2070{
2071 struct brcmf_scan_results *bss_list;
Roland Vossend34bf642011-10-18 14:03:01 +02002072 struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002073 s32 err = 0;
2074 int i;
2075
2076 bss_list = cfg_priv->bss_list;
2077 if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
2078 WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
2079 bss_list->version);
2080 return -EOPNOTSUPP;
2081 }
2082 WL_SCAN("scanned AP count (%d)\n", bss_list->count);
2083 for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
Roland Vossen6f09be02011-10-18 14:03:02 +02002084 bi = next_bss_le(bss_list, bi);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002085 err = brcmf_inform_single_bss(cfg_priv, bi);
2086 if (err)
2087 break;
2088 }
2089 return err;
2090}
2091
2092static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
2093 struct net_device *ndev, const u8 *bssid)
2094{
2095 struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
2096 struct ieee80211_channel *notify_channel;
Roland Vossend34bf642011-10-18 14:03:01 +02002097 struct brcmf_bss_info_le *bi = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002098 struct ieee80211_supported_band *band;
2099 u8 *buf = NULL;
2100 s32 err = 0;
2101 u16 channel;
2102 u32 freq;
2103 u64 notify_timestamp;
2104 u16 notify_capability;
2105 u16 notify_interval;
2106 u8 *notify_ie;
2107 size_t notify_ielen;
2108 s32 notify_signal;
2109
2110 WL_TRACE("Enter\n");
2111
2112 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2113 if (buf == NULL) {
2114 err = -ENOMEM;
2115 goto CleanUp;
2116 }
2117
2118 *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2119
2120 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
2121 if (err) {
2122 WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
2123 goto CleanUp;
2124 }
2125
Roland Vossend34bf642011-10-18 14:03:01 +02002126 bi = (struct brcmf_bss_info_le *)(buf + 4);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002127
2128 channel = bi->ctl_ch ? bi->ctl_ch :
2129 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2130
2131 if (channel <= CH_MAX_2G_CHANNEL)
2132 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2133 else
2134 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2135
2136 freq = ieee80211_channel_to_frequency(channel, band->band);
2137 notify_channel = ieee80211_get_channel(wiphy, freq);
2138
2139 notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
2140 notify_capability = le16_to_cpu(bi->capability);
2141 notify_interval = le16_to_cpu(bi->beacon_period);
2142 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2143 notify_ielen = le32_to_cpu(bi->ie_length);
2144 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2145
2146 WL_CONN("channel: %d(%d)\n", channel, freq);
2147 WL_CONN("capability: %X\n", notify_capability);
2148 WL_CONN("beacon interval: %d\n", notify_interval);
2149 WL_CONN("signal: %d\n", notify_signal);
2150 WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
2151
2152 cfg80211_inform_bss(wiphy, notify_channel, bssid,
2153 notify_timestamp, notify_capability, notify_interval,
2154 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2155
2156CleanUp:
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
2475static void brcmf_delay(u32 ms)
2476{
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) {
2783 WL_ERR("Couldn not allocate wiphy device\n");
2784 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) {
2809 WL_ERR("Couldn not register wiphy device (%d)\n", err);
2810 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/*
3295** push event to tail of the queue
3296*/
3297
3298static s32
3299brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
3300 const struct brcmf_event_msg *msg)
3301{
3302 struct brcmf_cfg80211_event_q *e;
3303 s32 err = 0;
3304
3305 e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
3306 if (!e)
3307 return -ENOMEM;
3308
3309 e->etype = event;
3310 memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
3311
3312 spin_lock_irq(&cfg_priv->evt_q_lock);
3313 list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
3314 spin_unlock_irq(&cfg_priv->evt_q_lock);
3315
3316 return err;
3317}
3318
3319static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
3320{
3321 kfree(e);
3322}
3323
3324static void brcmf_cfg80211_event_handler(struct work_struct *work)
3325{
3326 struct brcmf_cfg80211_priv *cfg_priv =
3327 container_of(work, struct brcmf_cfg80211_priv,
3328 event_work);
3329 struct brcmf_cfg80211_event_q *e;
3330
3331 e = brcmf_deq_event(cfg_priv);
3332 if (unlikely(!e)) {
3333 WL_ERR("event queue empty...\n");
3334 return;
3335 }
3336
3337 do {
3338 WL_INFO("event type (%d)\n", e->etype);
3339 if (cfg_priv->el.handler[e->etype])
3340 cfg_priv->el.handler[e->etype](cfg_priv,
3341 cfg_to_ndev(cfg_priv),
3342 &e->emsg, e->edata);
3343 else
3344 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
3345 brcmf_put_event(e);
3346 } while ((e = brcmf_deq_event(cfg_priv)));
3347
3348}
3349
3350static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv)
3351{
3352 spin_lock_init(&cfg_priv->evt_q_lock);
3353 INIT_LIST_HEAD(&cfg_priv->evt_q_list);
3354}
3355
3356static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv)
3357{
3358 struct brcmf_cfg80211_event_q *e;
3359
3360 spin_lock_irq(&cfg_priv->evt_q_lock);
3361 while (!list_empty(&cfg_priv->evt_q_list)) {
3362 e = list_first_entry(&cfg_priv->evt_q_list,
3363 struct brcmf_cfg80211_event_q, evt_q_list);
3364 list_del(&e->evt_q_list);
3365 kfree(e);
3366 }
3367 spin_unlock_irq(&cfg_priv->evt_q_lock);
3368}
3369
3370static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
3371{
3372 s32 err = 0;
3373
3374 cfg_priv->scan_request = NULL;
3375 cfg_priv->pwr_save = true;
3376 cfg_priv->iscan_on = true; /* iscan on & off switch.
3377 we enable iscan per default */
3378 cfg_priv->roam_on = true; /* roam on & off switch.
3379 we enable roam per default */
3380
3381 cfg_priv->iscan_kickstart = false;
3382 cfg_priv->active_scan = true; /* we do active scan for
3383 specific scan per default */
3384 cfg_priv->dongle_up = false; /* dongle is not up yet */
3385 brcmf_init_eq(cfg_priv);
3386 err = brcmf_init_priv_mem(cfg_priv);
3387 if (err)
3388 return err;
3389 INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler);
3390 brcmf_init_eloop_handler(&cfg_priv->el);
3391 mutex_init(&cfg_priv->usr_sync);
3392 err = brcmf_init_iscan(cfg_priv);
3393 if (err)
3394 return err;
3395 brcmf_init_conf(cfg_priv->conf);
3396 brcmf_init_prof(cfg_priv->profile);
3397 brcmf_link_down(cfg_priv);
3398
3399 return err;
3400}
3401
3402static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv)
3403{
3404 cancel_work_sync(&cfg_priv->event_work);
3405 cfg_priv->dongle_up = false; /* dongle down */
3406 brcmf_flush_eq(cfg_priv);
3407 brcmf_link_down(cfg_priv);
3408 brcmf_term_iscan(cfg_priv);
3409 brcmf_deinit_priv_mem(cfg_priv);
3410}
3411
3412struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
3413 struct device *busdev,
3414 void *data)
3415{
3416 struct wireless_dev *wdev;
3417 struct brcmf_cfg80211_priv *cfg_priv;
3418 struct brcmf_cfg80211_iface *ci;
3419 struct brcmf_cfg80211_dev *cfg_dev;
3420 s32 err = 0;
3421
3422 if (!ndev) {
3423 WL_ERR("ndev is invalid\n");
3424 return NULL;
3425 }
3426 cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL);
3427 if (!cfg_dev)
3428 return NULL;
3429
3430 wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev);
3431 if (IS_ERR(wdev)) {
3432 kfree(cfg_dev);
3433 return NULL;
3434 }
3435
3436 wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
3437 cfg_priv = wdev_to_cfg(wdev);
3438 cfg_priv->wdev = wdev;
3439 cfg_priv->pub = data;
3440 ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci;
3441 ci->cfg_priv = cfg_priv;
3442 ndev->ieee80211_ptr = wdev;
3443 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
3444 wdev->netdev = ndev;
3445 err = wl_init_priv(cfg_priv);
3446 if (err) {
3447 WL_ERR("Failed to init iwm_priv (%d)\n", err);
3448 goto cfg80211_attach_out;
3449 }
3450 brcmf_set_drvdata(cfg_dev, ci);
3451
3452 return cfg_dev;
3453
3454cfg80211_attach_out:
3455 brcmf_free_wdev(cfg_priv);
3456 kfree(cfg_dev);
3457 return NULL;
3458}
3459
3460void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev)
3461{
3462 struct brcmf_cfg80211_priv *cfg_priv;
3463
3464 cfg_priv = brcmf_priv_get(cfg_dev);
3465
3466 wl_deinit_priv(cfg_priv);
3467 brcmf_free_wdev(cfg_priv);
3468 brcmf_set_drvdata(cfg_dev, NULL);
3469 kfree(cfg_dev);
3470}
3471
3472void
3473brcmf_cfg80211_event(struct net_device *ndev,
3474 const struct brcmf_event_msg *e, void *data)
3475{
3476 u32 event_type = be32_to_cpu(e->event_type);
3477 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
3478
3479 if (!brcmf_enq_event(cfg_priv, event_type, e))
3480 schedule_work(&cfg_priv->event_work);
3481}
3482
3483static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
3484{
3485 s32 infra = 0;
3486 s32 err = 0;
3487
3488 switch (iftype) {
3489 case NL80211_IFTYPE_MONITOR:
3490 case NL80211_IFTYPE_WDS:
3491 WL_ERR("type (%d) : currently we do not support this mode\n",
3492 iftype);
3493 err = -EINVAL;
3494 return err;
3495 case NL80211_IFTYPE_ADHOC:
3496 infra = 0;
3497 break;
3498 case NL80211_IFTYPE_STATION:
3499 infra = 1;
3500 break;
3501 default:
3502 err = -EINVAL;
3503 WL_ERR("invalid type (%d)\n", iftype);
3504 return err;
3505 }
3506 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
3507 if (err) {
3508 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
3509 return err;
3510 }
3511
3512 return 0;
3513}
3514
3515static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
3516{
3517 /* Room for "event_msgs" + '\0' + bitvec */
3518 s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
3519 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
3520 s32 err = 0;
3521
3522 WL_TRACE("Enter\n");
3523
3524 /* Setup event_msgs */
Alwin Beukers53a22772011-10-12 20:51:30 +02003525 brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
3526 iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003527 err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
3528 if (err) {
3529 WL_ERR("Get event_msgs error (%d)\n", err);
3530 goto dongle_eventmsg_out;
3531 }
3532 memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
3533
3534 setbit(eventmask, BRCMF_E_SET_SSID);
3535 setbit(eventmask, BRCMF_E_ROAM);
3536 setbit(eventmask, BRCMF_E_PRUNE);
3537 setbit(eventmask, BRCMF_E_AUTH);
3538 setbit(eventmask, BRCMF_E_REASSOC);
3539 setbit(eventmask, BRCMF_E_REASSOC_IND);
3540 setbit(eventmask, BRCMF_E_DEAUTH_IND);
3541 setbit(eventmask, BRCMF_E_DISASSOC_IND);
3542 setbit(eventmask, BRCMF_E_DISASSOC);
3543 setbit(eventmask, BRCMF_E_JOIN);
3544 setbit(eventmask, BRCMF_E_ASSOC_IND);
3545 setbit(eventmask, BRCMF_E_PSK_SUP);
3546 setbit(eventmask, BRCMF_E_LINK);
3547 setbit(eventmask, BRCMF_E_NDIS_LINK);
3548 setbit(eventmask, BRCMF_E_MIC_ERROR);
3549 setbit(eventmask, BRCMF_E_PMKID_CACHE);
3550 setbit(eventmask, BRCMF_E_TXFAIL);
3551 setbit(eventmask, BRCMF_E_JOIN_START);
3552 setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
3553
Alwin Beukers53a22772011-10-12 20:51:30 +02003554 brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
3555 iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003556 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
3557 if (err) {
3558 WL_ERR("Set event_msgs error (%d)\n", err);
3559 goto dongle_eventmsg_out;
3560 }
3561
3562dongle_eventmsg_out:
3563 WL_TRACE("Exit\n");
3564 return err;
3565}
3566
3567static s32
3568brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
3569{
3570 s8 iovbuf[32];
Arend van Spriel5b435de2011-10-05 13:19:03 +02003571 s32 err = 0;
Arend van Sprielf588bc02011-10-12 20:51:22 +02003572 __le32 roamtrigger[2];
3573 __le32 roam_delta[2];
3574 __le32 bcn_to_le;
3575 __le32 roamvar_le;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003576
3577 /*
3578 * Setup timeout if Beacons are lost and roam is
3579 * off to report link down
3580 */
3581 if (roamvar) {
Arend van Sprielf588bc02011-10-12 20:51:22 +02003582 bcn_to_le = cpu_to_le32(bcn_timeout);
Alwin Beukers53a22772011-10-12 20:51:30 +02003583 brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le,
Arend van Sprielf588bc02011-10-12 20:51:22 +02003584 sizeof(bcn_to_le), iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003585 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR,
3586 iovbuf, sizeof(iovbuf));
3587 if (err) {
3588 WL_ERR("bcn_timeout error (%d)\n", err);
3589 goto dongle_rom_out;
3590 }
3591 }
3592
3593 /*
3594 * Enable/Disable built-in roaming to allow supplicant
3595 * to take care of roaming
3596 */
3597 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
Arend van Sprielf588bc02011-10-12 20:51:22 +02003598 roamvar_le = cpu_to_le32(roamvar);
Alwin Beukers53a22772011-10-12 20:51:30 +02003599 brcmf_c_mkiovar("roam_off", (char *)&roamvar_le,
Arend van Sprielf588bc02011-10-12 20:51:22 +02003600 sizeof(roamvar_le), iovbuf, sizeof(iovbuf));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003601 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
3602 if (err) {
3603 WL_ERR("roam_off error (%d)\n", err);
3604 goto dongle_rom_out;
3605 }
3606
Arend van Sprielf588bc02011-10-12 20:51:22 +02003607 roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
3608 roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003609 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER,
3610 (void *)roamtrigger, sizeof(roamtrigger));
3611 if (err) {
3612 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
3613 goto dongle_rom_out;
3614 }
3615
Arend van Sprielf588bc02011-10-12 20:51:22 +02003616 roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
3617 roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003618 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA,
3619 (void *)roam_delta, sizeof(roam_delta));
3620 if (err) {
3621 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
3622 goto dongle_rom_out;
3623 }
3624
3625dongle_rom_out:
3626 return err;
3627}
3628
3629static s32
3630brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003631 s32 scan_unassoc_time, s32 scan_passive_time)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003632{
3633 s32 err = 0;
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003634 __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time);
3635 __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time);
3636 __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003637
3638 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003639 &scan_assoc_tm_le, sizeof(scan_assoc_tm_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003640 if (err) {
3641 if (err == -EOPNOTSUPP)
3642 WL_INFO("Scan assoc time is not supported\n");
3643 else
3644 WL_ERR("Scan assoc time error (%d)\n", err);
3645 goto dongle_scantime_out;
3646 }
3647 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003648 &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003649 if (err) {
3650 if (err == -EOPNOTSUPP)
3651 WL_INFO("Scan unassoc time is not supported\n");
3652 else
3653 WL_ERR("Scan unassoc time error (%d)\n", err);
3654 goto dongle_scantime_out;
3655 }
3656
3657 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
Arend van Sprielc68cdc02011-10-12 20:51:23 +02003658 &scan_passive_tm_le, sizeof(scan_passive_tm_le));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003659 if (err) {
3660 if (err == -EOPNOTSUPP)
3661 WL_INFO("Scan passive time is not supported\n");
3662 else
3663 WL_ERR("Scan passive time error (%d)\n", err);
3664 goto dongle_scantime_out;
3665 }
3666
3667dongle_scantime_out:
3668 return err;
3669}
3670
3671static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv)
3672{
3673 struct wiphy *wiphy;
3674 s32 phy_list;
3675 s8 phy;
3676 s32 err = 0;
3677
3678 err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST,
3679 &phy_list, sizeof(phy_list));
3680 if (err) {
3681 WL_ERR("error (%d)\n", err);
3682 return err;
3683 }
3684
3685 phy = ((char *)&phy_list)[1];
3686 WL_INFO("%c phy\n", phy);
3687 if (phy == 'n' || phy == 'a') {
3688 wiphy = cfg_to_wiphy(cfg_priv);
3689 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
3690 }
3691
3692 return err;
3693}
3694
3695static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv)
3696{
3697 return wl_update_wiphybands(cfg_priv);
3698}
3699
3700static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv)
3701{
3702 struct net_device *ndev;
3703 struct wireless_dev *wdev;
3704 s32 power_mode;
3705 s32 err = 0;
3706
3707 if (cfg_priv->dongle_up)
3708 return err;
3709
3710 ndev = cfg_to_ndev(cfg_priv);
3711 wdev = ndev->ieee80211_ptr;
3712
3713 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
3714 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
3715
3716 err = brcmf_dongle_eventmsg(ndev);
3717 if (err)
3718 goto default_conf_out;
3719
3720 power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF;
3721 err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode);
3722 if (err)
3723 goto default_conf_out;
3724 WL_INFO("power save set to %s\n",
3725 (power_mode ? "enabled" : "disabled"));
3726
3727 err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1),
3728 WL_BEACON_TIMEOUT);
3729 if (err)
3730 goto default_conf_out;
3731 err = brcmf_dongle_mode(ndev, wdev->iftype);
3732 if (err && err != -EINPROGRESS)
3733 goto default_conf_out;
3734 err = brcmf_dongle_probecap(cfg_priv);
3735 if (err)
3736 goto default_conf_out;
3737
3738 /* -EINPROGRESS: Call commit handler */
3739
3740default_conf_out:
3741
3742 cfg_priv->dongle_up = true;
3743
3744 return err;
3745
3746}
3747
3748static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv)
3749{
3750 char buf[10+IFNAMSIZ];
3751 struct dentry *fd;
3752 s32 err = 0;
3753
3754 sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name);
3755 cfg_priv->debugfsdir = debugfs_create_dir(buf,
3756 cfg_to_wiphy(cfg_priv)->debugfsdir);
3757
3758 fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir,
3759 (u16 *)&cfg_priv->profile->beacon_interval);
3760 if (!fd) {
3761 err = -ENOMEM;
3762 goto err_out;
3763 }
3764
3765 fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir,
3766 (u8 *)&cfg_priv->profile->dtim_period);
3767 if (!fd) {
3768 err = -ENOMEM;
3769 goto err_out;
3770 }
3771
3772err_out:
3773 return err;
3774}
3775
3776static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv)
3777{
3778 debugfs_remove_recursive(cfg_priv->debugfsdir);
3779 cfg_priv->debugfsdir = NULL;
3780}
3781
3782static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv)
3783{
3784 s32 err = 0;
3785
3786 set_bit(WL_STATUS_READY, &cfg_priv->status);
3787
3788 brcmf_debugfs_add_netdev_params(cfg_priv);
3789
3790 err = brcmf_config_dongle(cfg_priv);
3791 if (err)
3792 return err;
3793
3794 brcmf_invoke_iscan(cfg_priv);
3795
3796 return err;
3797}
3798
3799static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv)
3800{
3801 /*
3802 * While going down, if associated with AP disassociate
3803 * from AP to save power
3804 */
3805 if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) ||
3806 test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
3807 test_bit(WL_STATUS_READY, &cfg_priv->status)) {
3808 WL_INFO("Disassociating from AP");
3809 brcmf_link_down(cfg_priv);
3810
3811 /* Make sure WPA_Supplicant receives all the event
3812 generated due to DISASSOC call to the fw to keep
3813 the state fw and WPA_Supplicant state consistent
3814 */
3815 brcmf_delay(500);
3816 }
3817
3818 set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
3819 brcmf_term_iscan(cfg_priv);
3820 if (cfg_priv->scan_request) {
3821 cfg80211_scan_done(cfg_priv->scan_request, true);
3822 /* May need to perform this to cover rmmod */
3823 /* wl_set_mpc(cfg_to_ndev(wl), 1); */
3824 cfg_priv->scan_request = NULL;
3825 }
3826 clear_bit(WL_STATUS_READY, &cfg_priv->status);
3827 clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
3828 clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
3829
3830 brcmf_debugfs_remove_netdev(cfg_priv);
3831
3832 return 0;
3833}
3834
3835s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev)
3836{
3837 struct brcmf_cfg80211_priv *cfg_priv;
3838 s32 err = 0;
3839
3840 cfg_priv = brcmf_priv_get(cfg_dev);
3841 mutex_lock(&cfg_priv->usr_sync);
3842 err = __brcmf_cfg80211_up(cfg_priv);
3843 mutex_unlock(&cfg_priv->usr_sync);
3844
3845 return err;
3846}
3847
3848s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev)
3849{
3850 struct brcmf_cfg80211_priv *cfg_priv;
3851 s32 err = 0;
3852
3853 cfg_priv = brcmf_priv_get(cfg_dev);
3854 mutex_lock(&cfg_priv->usr_sync);
3855 err = __brcmf_cfg80211_down(cfg_priv);
3856 mutex_unlock(&cfg_priv->usr_sync);
3857
3858 return err;
3859}
3860
3861static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
3862 u8 t, u8 l, u8 *v)
3863{
3864 struct brcmf_cfg80211_ie *ie = &cfg_priv->ie;
3865 s32 err = 0;
3866
3867 if (ie->offset + l + 2 > WL_TLV_INFO_MAX) {
3868 WL_ERR("ei crosses buffer boundary\n");
3869 return -ENOSPC;
3870 }
3871 ie->buf[ie->offset] = t;
3872 ie->buf[ie->offset + 1] = l;
3873 memcpy(&ie->buf[ie->offset + 2], v, l);
3874 ie->offset += l + 2;
3875
3876 return err;
3877}