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