staging: brcm80211: removed wlioctl.h and dhdioctl.h
[deliverable/linux.git] / drivers / staging / brcm80211 / brcmfmac / wl_cfg80211.c
CommitLineData
cf2b4488
HP
1/*
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
a1c16ed2
GKH
17#include <linux/kernel.h>
18#include <linux/if_arp.h>
cf2b4488
HP
19
20#include <bcmutils.h>
cf2b4488 21
cf2b4488
HP
22#include <asm/uaccess.h>
23
24#include <dngl_stats.h>
25#include <dhd.h>
cf2b4488 26
7716314b 27#include <linux/kthread.h>
cf2b4488
HP
28#include <linux/netdevice.h>
29#include <linux/sched.h>
30#include <linux/etherdevice.h>
31#include <linux/wireless.h>
32#include <linux/ieee80211.h>
33#include <net/cfg80211.h>
34
35#include <net/rtnetlink.h>
36#include <linux/mmc/sdio_func.h>
37#include <linux/firmware.h>
38#include <wl_cfg80211.h>
39
6b5a5a3e
GG
40void sdioh_sdio_set_host_pm_flags(int flag);
41
5f782dee
JC
42static struct sdio_func *cfg80211_sdio_func;
43static struct wl_dev *wl_cfg80211_dev;
a44d4236 44static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
cf2b4488 45
1ce4784e 46u32 wl_dbg_level = WL_DBG_ERR;
cf2b4488 47
a4ac0d84
HP
48#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4.bin"
49#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4.txt"
cf2b4488
HP
50
51/*
52** cfg80211_ops api/callback list
53*/
3e26416e 54static s32 wl_cfg80211_change_iface(struct wiphy *wiphy,
cf2b4488 55 struct net_device *ndev,
66cbd3ab 56 enum nl80211_iftype type, u32 *flags,
cf2b4488 57 struct vif_params *params);
3e26416e 58static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
cf2b4488
HP
59 struct cfg80211_scan_request *request,
60 struct cfg80211_ssid *this_ssid);
3e26416e 61static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
cf2b4488 62 struct cfg80211_scan_request *request);
3e26416e
GKH
63static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
64static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
cf2b4488 65 struct cfg80211_ibss_params *params);
3e26416e 66static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
cf2b4488 67 struct net_device *dev);
3e26416e 68static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
3fd79f7c 69 struct net_device *dev, u8 *mac,
cf2b4488 70 struct station_info *sinfo);
3e26416e 71static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
cf2b4488 72 struct net_device *dev, bool enabled,
3e26416e
GKH
73 s32 timeout);
74static s32 wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
cf2b4488 75 struct net_device *dev,
3fd79f7c 76 const u8 *addr,
cf2b4488
HP
77 const struct cfg80211_bitrate_mask
78 *mask);
79static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
80 struct cfg80211_connect_params *sme);
3e26416e 81static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
7d4df48e 82 u16 reason_code);
3e26416e 83static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
cf2b4488 84 enum nl80211_tx_power_setting type,
3e26416e
GKH
85 s32 dbm);
86static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
87static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
8a6257fb
AS
88 struct net_device *dev, u8 key_idx,
89 bool unicast, bool multicast);
3e26416e 90static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
34a488c1 91 u8 key_idx, bool pairwise, const u8 *mac_addr,
cf2b4488 92 struct key_params *params);
3e26416e 93static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
34a488c1 94 u8 key_idx, bool pairwise, const u8 *mac_addr);
3e26416e 95static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
34a488c1 96 u8 key_idx, bool pairwise, const u8 *mac_addr,
cf2b4488
HP
97 void *cookie, void (*callback) (void *cookie,
98 struct
99 key_params *
100 params));
3e26416e 101static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
cf2b4488 102 struct net_device *dev,
3fd79f7c 103 u8 key_idx);
3e26416e
GKH
104static s32 wl_cfg80211_resume(struct wiphy *wiphy);
105static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
106static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
cf2b4488 107 struct cfg80211_pmksa *pmksa);
3e26416e 108static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
cf2b4488 109 struct cfg80211_pmksa *pmksa);
3e26416e 110static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
cf2b4488
HP
111 struct net_device *dev);
112/*
113** event & event Q handlers for cfg80211 interfaces
114*/
3e26416e 115static s32 wl_create_event_handler(struct wl_priv *wl);
cf2b4488 116static void wl_destroy_event_handler(struct wl_priv *wl);
3e26416e 117static s32 wl_event_handler(void *data);
cf2b4488
HP
118static void wl_init_eq(struct wl_priv *wl);
119static void wl_flush_eq(struct wl_priv *wl);
120static void wl_lock_eq(struct wl_priv *wl);
121static void wl_unlock_eq(struct wl_priv *wl);
122static void wl_init_eq_lock(struct wl_priv *wl);
123static void wl_init_eloop_handler(struct wl_event_loop *el);
124static struct wl_event_q *wl_deq_event(struct wl_priv *wl);
3e26416e 125static s32 wl_enq_event(struct wl_priv *wl, u32 type,
cf2b4488
HP
126 const wl_event_msg_t *msg, void *data);
127static void wl_put_event(struct wl_event_q *e);
128static void wl_wakeup_event(struct wl_priv *wl);
3e26416e 129static s32 wl_notify_connect_status(struct wl_priv *wl,
cf2b4488
HP
130 struct net_device *ndev,
131 const wl_event_msg_t *e, void *data);
3e26416e 132static s32 wl_notify_roaming_status(struct wl_priv *wl,
cf2b4488
HP
133 struct net_device *ndev,
134 const wl_event_msg_t *e, void *data);
3e26416e 135static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
cf2b4488 136 const wl_event_msg_t *e, void *data);
3e26416e 137static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
b3164c71 138 const wl_event_msg_t *e, void *data,
139 bool completed);
3e26416e 140static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
cf2b4488 141 const wl_event_msg_t *e, void *data);
3e26416e 142static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
cf2b4488
HP
143 const wl_event_msg_t *e, void *data);
144
145/*
146** register/deregister sdio function
147*/
93ad12cf 148struct sdio_func *wl_cfg80211_get_sdio_func(void);
cf2b4488
HP
149static void wl_clear_sdio_func(void);
150
151/*
152** ioctl utilites
153*/
3e26416e
GKH
154static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
155 s32 buf_len);
156static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
157 s8 *buf, s32 len);
158static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
159static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
160 s32 *retval);
161static s32 wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg,
66cbd3ab 162 u32 len);
cf2b4488
HP
163
164/*
165** cfg80211 set_wiphy_params utilities
166*/
3e26416e
GKH
167static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
168static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
169static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
cf2b4488
HP
170
171/*
172** wl profile utilities
173*/
3e26416e
GKH
174static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
175 void *data, s32 item);
176static void *wl_read_prof(struct wl_priv *wl, s32 item);
cf2b4488
HP
177static void wl_init_prof(struct wl_profile *prof);
178
179/*
180** cfg80211 connect utilites
181*/
3e26416e 182static s32 wl_set_wpa_version(struct net_device *dev,
75494966 183 struct cfg80211_connect_params *sme);
3e26416e 184static s32 wl_set_auth_type(struct net_device *dev,
75494966 185 struct cfg80211_connect_params *sme);
3e26416e 186static s32 wl_set_set_cipher(struct net_device *dev,
75494966 187 struct cfg80211_connect_params *sme);
3e26416e 188static s32 wl_set_key_mgmt(struct net_device *dev,
75494966 189 struct cfg80211_connect_params *sme);
3e26416e 190static s32 wl_set_set_sharedkey(struct net_device *dev,
75494966 191 struct cfg80211_connect_params *sme);
3e26416e 192static s32 wl_get_assoc_ies(struct wl_priv *wl);
e494632e 193static void wl_clear_assoc_ies(struct wl_priv *wl);
fb693a71 194static void wl_ch_to_chanspec(int ch,
195 struct wl_join_params *join_params, size_t *join_params_size);
cf2b4488
HP
196
197/*
198** information element utilities
199*/
5dc56c9f 200static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v);
3e26416e 201static s32 wl_mode_to_nl80211_iftype(s32 mode);
3e26416e 202static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
75494966 203 struct device *dev);
cf2b4488 204static void wl_free_wdev(struct wl_priv *wl);
3e26416e
GKH
205static s32 wl_inform_bss(struct wl_priv *wl);
206static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
207static s32 wl_update_bss_info(struct wl_priv *wl);
3e26416e 208static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
75494966
SS
209 u8 key_idx, const u8 *mac_addr,
210 struct key_params *params);
cf2b4488
HP
211
212/*
213** key indianess swap utilities
214*/
215static void swap_key_from_BE(struct wl_wsec_key *key);
216static void swap_key_to_BE(struct wl_wsec_key *key);
217
218/*
219** wl_priv memory init/deinit utilities
220*/
3e26416e 221static s32 wl_init_priv_mem(struct wl_priv *wl);
cf2b4488
HP
222static void wl_deinit_priv_mem(struct wl_priv *wl);
223
66cbd3ab 224static void wl_delay(u32 ms);
cf2b4488
HP
225
226/*
227** store/restore cfg80211 instance data
228*/
229static void wl_set_drvdata(struct wl_dev *dev, void *data);
230static void *wl_get_drvdata(struct wl_dev *dev);
231
232/*
233** ibss mode utilities
234*/
235static bool wl_is_ibssmode(struct wl_priv *wl);
cf2b4488
HP
236
237/*
238** dongle up/down , default configuration utilities
239*/
240static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
241static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e);
b3164c71 242static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
cf2b4488 243static void wl_link_down(struct wl_priv *wl);
3e26416e
GKH
244static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype);
245static s32 __wl_cfg80211_up(struct wl_priv *wl);
246static s32 __wl_cfg80211_down(struct wl_priv *wl);
247static s32 wl_dongle_probecap(struct wl_priv *wl);
cf2b4488
HP
248static void wl_init_conf(struct wl_conf *conf);
249
250/*
251** dongle configuration utilities
252*/
253#ifndef EMBEDDED_PLATFORM
3e26416e
GKH
254static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype);
255static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
256static s32 wl_dongle_up(struct net_device *ndev, u32 up);
257static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
258static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
66cbd3ab 259 u32 dongle_align);
3e26416e
GKH
260static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
261 s32 arp_ol);
262static s32 wl_pattern_atoh(s8 *src, s8 *dst);
263static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
264static s32 wl_update_wiphybands(struct wl_priv *wl);
cf2b4488 265#endif /* !EMBEDDED_PLATFORM */
e494632e
SS
266
267static s32 wl_dongle_eventmsg(struct net_device *ndev);
e4dd6325
SS
268static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
269 s32 scan_unassoc_time, s32 scan_passive_time);
3e26416e 270static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
a1e962b6
SS
271static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
272 u32 bcn_timeout);
cf2b4488
HP
273
274/*
275** iscan handler
276*/
3deea904 277static void wl_iscan_timer(unsigned long data);
cf2b4488 278static void wl_term_iscan(struct wl_priv *wl);
3e26416e
GKH
279static s32 wl_init_iscan(struct wl_priv *wl);
280static s32 wl_iscan_thread(void *data);
281static s32 wl_dev_iovar_setbuf(struct net_device *dev, s8 *iovar,
282 void *param, s32 paramlen, void *bufptr,
283 s32 buflen);
284static s32 wl_dev_iovar_getbuf(struct net_device *dev, s8 *iovar,
285 void *param, s32 paramlen, void *bufptr,
286 s32 buflen);
287static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid,
7d4df48e 288 u16 action);
3e26416e
GKH
289static s32 wl_do_iscan(struct wl_priv *wl);
290static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan);
291static s32 wl_invoke_iscan(struct wl_priv *wl);
292static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
cf2b4488
HP
293 struct wl_scan_results **bss_list);
294static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted);
295static void wl_init_iscan_eloop(struct wl_iscan_eloop *el);
3e26416e
GKH
296static s32 wl_iscan_done(struct wl_priv *wl);
297static s32 wl_iscan_pending(struct wl_priv *wl);
298static s32 wl_iscan_inprogress(struct wl_priv *wl);
299static s32 wl_iscan_aborted(struct wl_priv *wl);
cf2b4488
HP
300
301/*
302** fw/nvram downloading handler
303*/
304static void wl_init_fw(struct wl_fw_ctrl *fw);
305
306/*
307* find most significant bit set
308*/
66cbd3ab 309static __used u32 wl_find_msb(u16 bit16);
cf2b4488
HP
310
311/*
312* update pmklist to dongle
313*/
3e26416e
GKH
314static __used s32 wl_update_pmklist(struct net_device *dev,
315 struct wl_pmk_list *pmk_list, s32 err);
cf2b4488 316
fb693a71 317static void wl_set_mpc(struct net_device *ndev, int mpc);
318
cd389a34 319/*
320* debufs support
321*/
322static int wl_debugfs_add_netdev_params(struct wl_priv *wl);
323static void wl_debugfs_remove_netdev(struct wl_priv *wl);
324
cf2b4488
HP
325#define WL_PRIV_GET() \
326 ({ \
327 struct wl_iface *ci; \
328 if (unlikely(!(wl_cfg80211_dev && \
329 (ci = wl_get_drvdata(wl_cfg80211_dev))))) { \
f4528696 330 WL_ERR("wl_cfg80211_dev is unavailable\n"); \
cf2b4488
HP
331 BUG(); \
332 } \
333 ci_to_wl(ci); \
334})
335
336#define CHECK_SYS_UP() \
337do { \
338 struct wl_priv *wl = wiphy_to_wl(wiphy); \
339 if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \
f4528696
JP
340 WL_INFO("device is not ready : status (%d)\n", \
341 (int)wl->status); \
cf2b4488
HP
342 return -EIO; \
343 } \
344} while (0)
345
346extern int dhd_wait_pend8021x(struct net_device *dev);
cf2b4488
HP
347#define CHAN2G(_channel, _freq, _flags) { \
348 .band = IEEE80211_BAND_2GHZ, \
349 .center_freq = (_freq), \
350 .hw_value = (_channel), \
351 .flags = (_flags), \
352 .max_antenna_gain = 0, \
353 .max_power = 30, \
354}
355
356#define CHAN5G(_channel, _flags) { \
357 .band = IEEE80211_BAND_5GHZ, \
358 .center_freq = 5000 + (5 * (_channel)), \
359 .hw_value = (_channel), \
360 .flags = (_flags), \
361 .max_antenna_gain = 0, \
362 .max_power = 30, \
363}
364
365#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
366#define RATETAB_ENT(_rateid, _flags) \
367 { \
368 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
369 .hw_value = (_rateid), \
370 .flags = (_flags), \
371 }
372
373static struct ieee80211_rate __wl_rates[] = {
374 RATETAB_ENT(WLC_RATE_1M, 0),
375 RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
376 RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
377 RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
378 RATETAB_ENT(WLC_RATE_6M, 0),
379 RATETAB_ENT(WLC_RATE_9M, 0),
380 RATETAB_ENT(WLC_RATE_12M, 0),
381 RATETAB_ENT(WLC_RATE_18M, 0),
382 RATETAB_ENT(WLC_RATE_24M, 0),
383 RATETAB_ENT(WLC_RATE_36M, 0),
384 RATETAB_ENT(WLC_RATE_48M, 0),
385 RATETAB_ENT(WLC_RATE_54M, 0),
386};
387
388#define wl_a_rates (__wl_rates + 4)
389#define wl_a_rates_size 8
390#define wl_g_rates (__wl_rates + 0)
391#define wl_g_rates_size 12
392
393static struct ieee80211_channel __wl_2ghz_channels[] = {
394 CHAN2G(1, 2412, 0),
395 CHAN2G(2, 2417, 0),
396 CHAN2G(3, 2422, 0),
397 CHAN2G(4, 2427, 0),
398 CHAN2G(5, 2432, 0),
399 CHAN2G(6, 2437, 0),
400 CHAN2G(7, 2442, 0),
401 CHAN2G(8, 2447, 0),
402 CHAN2G(9, 2452, 0),
403 CHAN2G(10, 2457, 0),
404 CHAN2G(11, 2462, 0),
405 CHAN2G(12, 2467, 0),
406 CHAN2G(13, 2472, 0),
407 CHAN2G(14, 2484, 0),
408};
409
410static struct ieee80211_channel __wl_5ghz_a_channels[] = {
411 CHAN5G(34, 0), CHAN5G(36, 0),
412 CHAN5G(38, 0), CHAN5G(40, 0),
413 CHAN5G(42, 0), CHAN5G(44, 0),
414 CHAN5G(46, 0), CHAN5G(48, 0),
415 CHAN5G(52, 0), CHAN5G(56, 0),
416 CHAN5G(60, 0), CHAN5G(64, 0),
417 CHAN5G(100, 0), CHAN5G(104, 0),
418 CHAN5G(108, 0), CHAN5G(112, 0),
419 CHAN5G(116, 0), CHAN5G(120, 0),
420 CHAN5G(124, 0), CHAN5G(128, 0),
421 CHAN5G(132, 0), CHAN5G(136, 0),
422 CHAN5G(140, 0), CHAN5G(149, 0),
423 CHAN5G(153, 0), CHAN5G(157, 0),
424 CHAN5G(161, 0), CHAN5G(165, 0),
425 CHAN5G(184, 0), CHAN5G(188, 0),
426 CHAN5G(192, 0), CHAN5G(196, 0),
427 CHAN5G(200, 0), CHAN5G(204, 0),
428 CHAN5G(208, 0), CHAN5G(212, 0),
429 CHAN5G(216, 0),
430};
431
432static struct ieee80211_channel __wl_5ghz_n_channels[] = {
433 CHAN5G(32, 0), CHAN5G(34, 0),
434 CHAN5G(36, 0), CHAN5G(38, 0),
435 CHAN5G(40, 0), CHAN5G(42, 0),
436 CHAN5G(44, 0), CHAN5G(46, 0),
437 CHAN5G(48, 0), CHAN5G(50, 0),
438 CHAN5G(52, 0), CHAN5G(54, 0),
439 CHAN5G(56, 0), CHAN5G(58, 0),
440 CHAN5G(60, 0), CHAN5G(62, 0),
441 CHAN5G(64, 0), CHAN5G(66, 0),
442 CHAN5G(68, 0), CHAN5G(70, 0),
443 CHAN5G(72, 0), CHAN5G(74, 0),
444 CHAN5G(76, 0), CHAN5G(78, 0),
445 CHAN5G(80, 0), CHAN5G(82, 0),
446 CHAN5G(84, 0), CHAN5G(86, 0),
447 CHAN5G(88, 0), CHAN5G(90, 0),
448 CHAN5G(92, 0), CHAN5G(94, 0),
449 CHAN5G(96, 0), CHAN5G(98, 0),
450 CHAN5G(100, 0), CHAN5G(102, 0),
451 CHAN5G(104, 0), CHAN5G(106, 0),
452 CHAN5G(108, 0), CHAN5G(110, 0),
453 CHAN5G(112, 0), CHAN5G(114, 0),
454 CHAN5G(116, 0), CHAN5G(118, 0),
455 CHAN5G(120, 0), CHAN5G(122, 0),
456 CHAN5G(124, 0), CHAN5G(126, 0),
457 CHAN5G(128, 0), CHAN5G(130, 0),
458 CHAN5G(132, 0), CHAN5G(134, 0),
459 CHAN5G(136, 0), CHAN5G(138, 0),
460 CHAN5G(140, 0), CHAN5G(142, 0),
461 CHAN5G(144, 0), CHAN5G(145, 0),
462 CHAN5G(146, 0), CHAN5G(147, 0),
463 CHAN5G(148, 0), CHAN5G(149, 0),
464 CHAN5G(150, 0), CHAN5G(151, 0),
465 CHAN5G(152, 0), CHAN5G(153, 0),
466 CHAN5G(154, 0), CHAN5G(155, 0),
467 CHAN5G(156, 0), CHAN5G(157, 0),
468 CHAN5G(158, 0), CHAN5G(159, 0),
469 CHAN5G(160, 0), CHAN5G(161, 0),
470 CHAN5G(162, 0), CHAN5G(163, 0),
471 CHAN5G(164, 0), CHAN5G(165, 0),
472 CHAN5G(166, 0), CHAN5G(168, 0),
473 CHAN5G(170, 0), CHAN5G(172, 0),
474 CHAN5G(174, 0), CHAN5G(176, 0),
475 CHAN5G(178, 0), CHAN5G(180, 0),
476 CHAN5G(182, 0), CHAN5G(184, 0),
477 CHAN5G(186, 0), CHAN5G(188, 0),
478 CHAN5G(190, 0), CHAN5G(192, 0),
479 CHAN5G(194, 0), CHAN5G(196, 0),
480 CHAN5G(198, 0), CHAN5G(200, 0),
481 CHAN5G(202, 0), CHAN5G(204, 0),
482 CHAN5G(206, 0), CHAN5G(208, 0),
483 CHAN5G(210, 0), CHAN5G(212, 0),
484 CHAN5G(214, 0), CHAN5G(216, 0),
485 CHAN5G(218, 0), CHAN5G(220, 0),
486 CHAN5G(222, 0), CHAN5G(224, 0),
487 CHAN5G(226, 0), CHAN5G(228, 0),
488};
489
490static struct ieee80211_supported_band __wl_band_2ghz = {
491 .band = IEEE80211_BAND_2GHZ,
492 .channels = __wl_2ghz_channels,
493 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
494 .bitrates = wl_g_rates,
495 .n_bitrates = wl_g_rates_size,
496};
497
498static struct ieee80211_supported_band __wl_band_5ghz_a = {
499 .band = IEEE80211_BAND_5GHZ,
500 .channels = __wl_5ghz_a_channels,
501 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
502 .bitrates = wl_a_rates,
503 .n_bitrates = wl_a_rates_size,
504};
505
506static struct ieee80211_supported_band __wl_band_5ghz_n = {
507 .band = IEEE80211_BAND_5GHZ,
508 .channels = __wl_5ghz_n_channels,
509 .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
510 .bitrates = wl_a_rates,
511 .n_bitrates = wl_a_rates_size,
512};
513
66cbd3ab 514static const u32 __wl_cipher_suites[] = {
cf2b4488
HP
515 WLAN_CIPHER_SUITE_WEP40,
516 WLAN_CIPHER_SUITE_WEP104,
517 WLAN_CIPHER_SUITE_TKIP,
518 WLAN_CIPHER_SUITE_CCMP,
519 WLAN_CIPHER_SUITE_AES_CMAC,
520};
521
522static void swap_key_from_BE(struct wl_wsec_key *key)
523{
29750b90
SF
524 key->index = cpu_to_le32(key->index);
525 key->len = cpu_to_le32(key->len);
526 key->algo = cpu_to_le32(key->algo);
527 key->flags = cpu_to_le32(key->flags);
528 key->rxiv.hi = cpu_to_le32(key->rxiv.hi);
529 key->rxiv.lo = cpu_to_le16(key->rxiv.lo);
530 key->iv_initialized = cpu_to_le32(key->iv_initialized);
cf2b4488
HP
531}
532
533static void swap_key_to_BE(struct wl_wsec_key *key)
534{
29750b90
SF
535 key->index = le32_to_cpu(key->index);
536 key->len = le32_to_cpu(key->len);
537 key->algo = le32_to_cpu(key->algo);
538 key->flags = le32_to_cpu(key->flags);
539 key->rxiv.hi = le32_to_cpu(key->rxiv.hi);
540 key->rxiv.lo = le16_to_cpu(key->rxiv.lo);
541 key->iv_initialized = le32_to_cpu(key->iv_initialized);
cf2b4488
HP
542}
543
3e26416e 544static s32
66cbd3ab 545wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
cf2b4488
HP
546{
547 struct ifreq ifr;
548 struct wl_ioctl ioc;
549 mm_segment_t fs;
3e26416e 550 s32 err = 0;
cf2b4488
HP
551
552 memset(&ioc, 0, sizeof(ioc));
553 ioc.cmd = cmd;
554 ioc.buf = arg;
555 ioc.len = len;
556 strcpy(ifr.ifr_name, dev->name);
557 ifr.ifr_data = (caddr_t)&ioc;
558
559 fs = get_fs();
560 set_fs(get_ds());
561 err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
562 set_fs(fs);
563
564 return err;
565}
566
3e26416e 567static s32
cf2b4488 568wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
66cbd3ab 569 enum nl80211_iftype type, u32 *flags,
cf2b4488
HP
570 struct vif_params *params)
571{
572 struct wl_priv *wl = wiphy_to_wl(wiphy);
573 struct wireless_dev *wdev;
3e26416e 574 s32 infra = 0;
3e26416e 575 s32 err = 0;
cf2b4488 576
1ce4784e 577 WL_TRACE("Enter\n");
cf2b4488 578 CHECK_SYS_UP();
69274f02 579
cf2b4488
HP
580 switch (type) {
581 case NL80211_IFTYPE_MONITOR:
582 case NL80211_IFTYPE_WDS:
f4528696
JP
583 WL_ERR("type (%d) : currently we do not support this type\n",
584 type);
cf2b4488
HP
585 return -EOPNOTSUPP;
586 case NL80211_IFTYPE_ADHOC:
587 wl->conf->mode = WL_MODE_IBSS;
69274f02 588 infra = 0;
cf2b4488
HP
589 break;
590 case NL80211_IFTYPE_STATION:
591 wl->conf->mode = WL_MODE_BSS;
592 infra = 1;
593 break;
594 default:
69274f02
SS
595 err = -EINVAL;
596 goto done;
cf2b4488 597 }
69274f02 598
29750b90 599 infra = cpu_to_le32(infra);
76c06459
JC
600 err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
601 if (unlikely(err)) {
f4528696 602 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
69274f02
SS
603 err = -EAGAIN;
604 } else {
605 wdev = ndev->ieee80211_ptr;
606 wdev->iftype = type;
cf2b4488 607 }
76c06459 608
69274f02
SS
609 WL_INFO("IF Type = %s\n",
610 (wl->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra");
611
612done:
1ce4784e
SS
613 WL_TRACE("Exit\n");
614
69274f02 615 return err;
cf2b4488
HP
616}
617
618static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
619{
a44d4236 620 memcpy(params->bssid, ether_bcast, ETH_ALEN);
cf2b4488
HP
621 params->bss_type = DOT11_BSSTYPE_ANY;
622 params->scan_type = 0;
623 params->nprobes = -1;
624 params->active_time = -1;
625 params->passive_time = -1;
626 params->home_time = -1;
627 params->channel_num = 0;
628
29750b90
SF
629 params->nprobes = cpu_to_le32(params->nprobes);
630 params->active_time = cpu_to_le32(params->active_time);
631 params->passive_time = cpu_to_le32(params->passive_time);
632 params->home_time = cpu_to_le32(params->home_time);
cf2b4488
HP
633 if (ssid && ssid->SSID_len)
634 memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
635
636}
637
3e26416e 638static s32
562c8850 639wl_dev_iovar_setbuf(struct net_device *dev, s8 * iovar, void *param,
3e26416e 640 s32 paramlen, void *bufptr, s32 buflen)
cf2b4488 641{
3e26416e 642 s32 iolen;
cf2b4488
HP
643
644 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
d7ddd169 645 BUG_ON(!iolen);
cf2b4488
HP
646
647 return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
648}
649
3e26416e 650static s32
562c8850 651wl_dev_iovar_getbuf(struct net_device *dev, s8 * iovar, void *param,
3e26416e 652 s32 paramlen, void *bufptr, s32 buflen)
cf2b4488 653{
3e26416e 654 s32 iolen;
cf2b4488
HP
655
656 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
d7ddd169 657 BUG_ON(!iolen);
cf2b4488
HP
658
659 return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen);
660}
661
3e26416e 662static s32
7d4df48e 663wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action)
cf2b4488 664{
3e26416e 665 s32 params_size =
ce0f1b8c 666 (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
cf2b4488 667 struct wl_iscan_params *params;
3e26416e 668 s32 err = 0;
cf2b4488
HP
669
670 if (ssid && ssid->SSID_len)
671 params_size += sizeof(struct wlc_ssid);
3b785a8c 672 params = kzalloc(params_size, GFP_KERNEL);
cf2b4488
HP
673 if (unlikely(!params))
674 return -ENOMEM;
d7ddd169 675 BUG_ON(params_size >= WLC_IOCTL_SMLEN);
cf2b4488
HP
676
677 wl_iscan_prep(&params->params, ssid);
678
29750b90
SF
679 params->version = cpu_to_le32(ISCAN_REQ_VERSION);
680 params->action = cpu_to_le16(action);
681 params->scan_duration = cpu_to_le16(0);
cf2b4488 682
ce0f1b8c 683 /* params_size += offsetof(wl_iscan_params_t, params); */
76c06459
JC
684 err = wl_dev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
685 iscan->ioctl_buf, WLC_IOCTL_SMLEN);
686 if (unlikely(err)) {
cf2b4488 687 if (err == -EBUSY) {
f4528696 688 WL_INFO("system busy : iscan canceled\n");
cf2b4488 689 } else {
f4528696 690 WL_ERR("error (%d)\n", err);
cf2b4488
HP
691 }
692 }
693 kfree(params);
694 return err;
695}
696
3e26416e 697static s32 wl_do_iscan(struct wl_priv *wl)
cf2b4488
HP
698{
699 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
fb693a71 700 struct net_device *ndev = wl_to_ndev(wl);
cf2b4488 701 struct wlc_ssid ssid;
c5ca038f 702 s32 passive_scan;
3e26416e 703 s32 err = 0;
cf2b4488
HP
704
705 /* Broadcast scan by default */
706 memset(&ssid, 0, sizeof(ssid));
707
708 iscan->state = WL_ISCAN_STATE_SCANING;
709
c5ca038f 710 passive_scan = wl->active_scan ? 0 : 1;
711 err = wl_dev_ioctl(wl_to_ndev(wl), WLC_SET_PASSIVE_SCAN,
712 &passive_scan, sizeof(passive_scan));
713 if (unlikely(err)) {
1ce4784e 714 WL_ERR("error (%d)\n", err);
c5ca038f 715 return err;
cf2b4488 716 }
fb693a71 717 wl_set_mpc(ndev, 0);
0f0881b0 718 wl->iscan_kickstart = true;
cf2b4488
HP
719 wl_run_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
720 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
721 iscan->timer_on = 1;
722
723 return err;
724}
725
3e26416e 726static s32
cf2b4488
HP
727__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
728 struct cfg80211_scan_request *request,
729 struct cfg80211_ssid *this_ssid)
730{
731 struct wl_priv *wl = ndev_to_wl(ndev);
732 struct cfg80211_ssid *ssids;
733 struct wl_scan_req *sr = wl_to_sr(wl);
c5ca038f 734 s32 passive_scan;
cf2b4488
HP
735 bool iscan_req;
736 bool spec_scan;
3e26416e 737 s32 err = 0;
cf2b4488
HP
738
739 if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) {
f4528696 740 WL_ERR("Scanning already : status (%d)\n", (int)wl->status);
cf2b4488
HP
741 return -EAGAIN;
742 }
743 if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) {
f4528696
JP
744 WL_ERR("Scanning being aborted : status (%d)\n",
745 (int)wl->status);
cf2b4488
HP
746 return -EAGAIN;
747 }
9446af06
SS
748 if (test_bit(WL_STATUS_CONNECTING, &wl->status)) {
749 WL_ERR("Connecting : status (%d)\n",
750 (int)wl->status);
751 return -EAGAIN;
752 }
cf2b4488 753
0965ae88
GKH
754 iscan_req = false;
755 spec_scan = false;
9446af06
SS
756 if (request) {
757 /* scan bss */
cf2b4488 758 ssids = request->ssids;
9446af06 759 if (wl->iscan_on && (!ssids || !ssids->ssid_len))
0f0881b0 760 iscan_req = true;
9446af06
SS
761 } else {
762 /* scan in ibss */
cf2b4488
HP
763 /* we don't do iscan in ibss */
764 ssids = this_ssid;
cf2b4488 765 }
9446af06 766
cf2b4488
HP
767 wl->scan_request = request;
768 set_bit(WL_STATUS_SCANNING, &wl->status);
769 if (iscan_req) {
76c06459 770 err = wl_do_iscan(wl);
fb693a71 771 if (likely(!err))
cf2b4488
HP
772 return err;
773 else
774 goto scan_out;
775 } else {
1ce4784e 776 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
f4528696 777 ssids->ssid, ssids->ssid_len);
cf2b4488 778 memset(&sr->ssid, 0, sizeof(sr->ssid));
93ad12cf 779 sr->ssid.SSID_len =
b61640d1 780 min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
93ad12cf 781 if (sr->ssid.SSID_len) {
782 memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
29750b90 783 sr->ssid.SSID_len = cpu_to_le32(sr->ssid.SSID_len);
0f0881b0 784 spec_scan = true;
cf2b4488 785 } else {
1ce4784e 786 WL_SCAN("Broadcast scan\n");
cf2b4488 787 }
1ce4784e 788
c5ca038f 789 passive_scan = wl->active_scan ? 0 : 1;
790 err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
791 &passive_scan, sizeof(passive_scan));
792 if (unlikely(err)) {
f4528696 793 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
c5ca038f 794 goto scan_out;
cf2b4488 795 }
fb693a71 796 wl_set_mpc(ndev, 0);
76c06459
JC
797 err = wl_dev_ioctl(ndev, WLC_SCAN, &sr->ssid,
798 sizeof(sr->ssid));
799 if (err) {
cf2b4488 800 if (err == -EBUSY) {
f4528696
JP
801 WL_INFO("system busy : scan for \"%s\" canceled\n",
802 sr->ssid.SSID);
cf2b4488 803 } else {
f4528696 804 WL_ERR("WLC_SCAN error (%d)\n", err);
cf2b4488 805 }
fb693a71 806 wl_set_mpc(ndev, 1);
cf2b4488
HP
807 goto scan_out;
808 }
809 }
810
811 return 0;
812
813scan_out:
814 clear_bit(WL_STATUS_SCANNING, &wl->status);
815 wl->scan_request = NULL;
816 return err;
817}
818
3e26416e 819static s32
cf2b4488
HP
820wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
821 struct cfg80211_scan_request *request)
822{
3e26416e 823 s32 err = 0;
cf2b4488 824
1ce4784e
SS
825 WL_TRACE("Enter\n");
826
cf2b4488 827 CHECK_SYS_UP();
1ce4784e 828
76c06459 829 err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
1ce4784e
SS
830 if (unlikely(err))
831 WL_ERR("scan error (%d)\n", err);
cf2b4488 832
1ce4784e 833 WL_TRACE("Exit\n");
cf2b4488
HP
834 return err;
835}
836
3e26416e 837static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
cf2b4488 838{
562c8850 839 s8 buf[WLC_IOCTL_SMLEN];
66cbd3ab 840 u32 len;
3e26416e 841 s32 err = 0;
cf2b4488 842
29750b90 843 val = cpu_to_le32(val);
cf2b4488 844 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
d7ddd169 845 BUG_ON(!len);
cf2b4488 846
76c06459 847 err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len);
1ce4784e 848 if (unlikely(err))
f4528696 849 WL_ERR("error (%d)\n", err);
cf2b4488
HP
850
851 return err;
852}
853
3e26416e
GKH
854static s32
855wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
cf2b4488
HP
856{
857 union {
562c8850 858 s8 buf[WLC_IOCTL_SMLEN];
3e26416e 859 s32 val;
cf2b4488 860 } var;
66cbd3ab
GKH
861 u32 len;
862 u32 data_null;
3e26416e 863 s32 err = 0;
cf2b4488
HP
864
865 len =
866 bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
867 sizeof(var.buf));
d7ddd169 868 BUG_ON(!len);
76c06459 869 err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len);
1ce4784e 870 if (unlikely(err))
f4528696 871 WL_ERR("error (%d)\n", err);
1ce4784e 872
29750b90 873 *retval = le32_to_cpu(var.val);
cf2b4488
HP
874
875 return err;
876}
877
3e26416e 878static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
cf2b4488 879{
3e26416e 880 s32 err = 0;
cf2b4488 881
76c06459 882 err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
1ce4784e 883 if (unlikely(err))
f4528696 884 WL_ERR("Error (%d)\n", err);
1ce4784e 885
cf2b4488
HP
886 return err;
887}
888
3e26416e 889static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
cf2b4488 890{
3e26416e 891 s32 err = 0;
cf2b4488 892
76c06459 893 err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
1ce4784e 894 if (unlikely(err))
f4528696 895 WL_ERR("Error (%d)\n", err);
1ce4784e 896
cf2b4488
HP
897 return err;
898}
899
3e26416e 900static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
cf2b4488 901{
3e26416e 902 s32 err = 0;
66cbd3ab 903 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
cf2b4488 904
29750b90 905 retry = cpu_to_le32(retry);
76c06459
JC
906 err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry));
907 if (unlikely(err)) {
f4528696 908 WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
cf2b4488
HP
909 return err;
910 }
911 return err;
912}
913
3e26416e 914static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
cf2b4488
HP
915{
916 struct wl_priv *wl = wiphy_to_wl(wiphy);
917 struct net_device *ndev = wl_to_ndev(wl);
3e26416e 918 s32 err = 0;
cf2b4488 919
1ce4784e 920 WL_TRACE("Enter\n");
cf2b4488 921 CHECK_SYS_UP();
1ce4784e 922
cf2b4488
HP
923 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
924 (wl->conf->rts_threshold != wiphy->rts_threshold)) {
925 wl->conf->rts_threshold = wiphy->rts_threshold;
76c06459
JC
926 err = wl_set_rts(ndev, wl->conf->rts_threshold);
927 if (!err)
1ce4784e 928 goto done;
cf2b4488
HP
929 }
930 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
931 (wl->conf->frag_threshold != wiphy->frag_threshold)) {
932 wl->conf->frag_threshold = wiphy->frag_threshold;
76c06459
JC
933 err = wl_set_frag(ndev, wl->conf->frag_threshold);
934 if (!err)
1ce4784e 935 goto done;
cf2b4488
HP
936 }
937 if (changed & WIPHY_PARAM_RETRY_LONG
938 && (wl->conf->retry_long != wiphy->retry_long)) {
939 wl->conf->retry_long = wiphy->retry_long;
0f0881b0 940 err = wl_set_retry(ndev, wl->conf->retry_long, true);
76c06459 941 if (!err)
1ce4784e 942 goto done;
cf2b4488
HP
943 }
944 if (changed & WIPHY_PARAM_RETRY_SHORT
945 && (wl->conf->retry_short != wiphy->retry_short)) {
946 wl->conf->retry_short = wiphy->retry_short;
0965ae88 947 err = wl_set_retry(ndev, wl->conf->retry_short, false);
1ce4784e
SS
948 if (!err)
949 goto done;
cf2b4488
HP
950 }
951
1ce4784e
SS
952done:
953 WL_TRACE("Exit\n");
cf2b4488
HP
954 return err;
955}
956
3e26416e 957static s32
cf2b4488
HP
958wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
959 struct cfg80211_ibss_params *params)
960{
961 struct wl_priv *wl = wiphy_to_wl(wiphy);
cf2b4488 962 struct wl_join_params join_params;
69274f02 963 size_t join_params_size = 0;
3e26416e 964 s32 err = 0;
69274f02
SS
965 s32 wsec = 0;
966 s32 bcnprd;
cf2b4488 967
1ce4784e 968 WL_TRACE("Enter\n");
cf2b4488 969 CHECK_SYS_UP();
69274f02
SS
970
971 if (params->ssid)
1ce4784e 972 WL_CONN("SSID: %s\n", params->ssid);
69274f02 973 else {
1ce4784e 974 WL_CONN("SSID: NULL, Not supported\n");
cf2b4488
HP
975 return -EOPNOTSUPP;
976 }
69274f02
SS
977
978 if (params->bssid)
1ce4784e 979 WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n",
69274f02
SS
980 params->bssid[0], params->bssid[1], params->bssid[2],
981 params->bssid[3], params->bssid[4], params->bssid[5]);
982 else
1ce4784e 983 WL_CONN("No BSSID specified\n");
69274f02
SS
984
985 if (params->channel)
1ce4784e 986 WL_CONN("channel: %d\n", params->channel->center_freq);
69274f02 987 else
1ce4784e 988 WL_CONN("no channel specified\n");
69274f02
SS
989
990 if (params->channel_fixed)
1ce4784e 991 WL_CONN("fixed channel required\n");
69274f02 992 else
1ce4784e 993 WL_CONN("no fixed channel required\n");
69274f02
SS
994
995 if (params->ie && params->ie_len)
1ce4784e 996 WL_CONN("ie len: %d\n", params->ie_len);
69274f02 997 else
1ce4784e 998 WL_CONN("no ie specified\n");
69274f02
SS
999
1000 if (params->beacon_interval)
1ce4784e 1001 WL_CONN("beacon interval: %d\n", params->beacon_interval);
69274f02 1002 else
1ce4784e 1003 WL_CONN("no beacon interval specified\n");
69274f02
SS
1004
1005 if (params->basic_rates)
1ce4784e 1006 WL_CONN("basic rates: %08X\n", params->basic_rates);
69274f02 1007 else
1ce4784e 1008 WL_CONN("no basic rates specified\n");
69274f02
SS
1009
1010 if (params->privacy)
1ce4784e 1011 WL_CONN("privacy required\n");
69274f02 1012 else
1ce4784e 1013 WL_CONN("no privacy required\n");
69274f02
SS
1014
1015 /* Configure Privacy for starter */
1016 if (params->privacy)
1017 wsec |= WEP_ENABLED;
1018
1019 err = wl_dev_intvar_set(dev, "wsec", wsec);
1020 if (unlikely(err)) {
1021 WL_ERR("wsec failed (%d)\n", err);
1022 goto done;
1023 }
1024
1025 /* Configure Beacon Interval for starter */
1026 if (params->beacon_interval)
1027 bcnprd = cpu_to_le32(params->beacon_interval);
1028 else
1029 bcnprd = cpu_to_le32(100);
1030
1031 err = wl_dev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd));
1032 if (unlikely(err)) {
1033 WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
1034 goto done;
cf2b4488 1035 }
69274f02
SS
1036
1037 /* Configure required join parameter */
1038 memset(&join_params, 0, sizeof(wl_join_params_t));
1039
1040 /* SSID */
1041 join_params.ssid.SSID_len =
1042 (params->ssid_len > 32) ? 32 : params->ssid_len;
1043 memcpy(join_params.ssid.SSID, params->ssid, join_params.ssid.SSID_len);
1044 join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
1045 join_params_size = sizeof(join_params.ssid);
1046 wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
1047
1048 /* BSSID */
1049 if (params->bssid) {
1050 memcpy(join_params.params.bssid, params->bssid, ETH_ALEN);
1051 join_params_size =
1052 sizeof(join_params.ssid) + WL_ASSOC_PARAMS_FIXED_SIZE;
cf2b4488 1053 } else {
69274f02 1054 memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
cf2b4488 1055 }
69274f02
SS
1056 wl_update_prof(wl, NULL, &join_params.params.bssid, WL_PROF_BSSID);
1057
1058 /* Channel */
1059 if (params->channel) {
1060 u32 target_channel;
1061
1062 wl->channel =
1063 ieee80211_frequency_to_channel(
1064 params->channel->center_freq);
1065 if (params->channel_fixed) {
1066 /* adding chanspec */
1067 wl_ch_to_chanspec(wl->channel,
1068 &join_params, &join_params_size);
1069 }
cf2b4488 1070
69274f02
SS
1071 /* set channel for starter */
1072 target_channel = cpu_to_le32(wl->channel);
1073 err = wl_dev_ioctl(dev, WLC_SET_CHANNEL,
1074 &target_channel, sizeof(target_channel));
1075 if (unlikely(err)) {
1076 WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
1077 goto done;
1078 }
1079 } else
1080 wl->channel = 0;
1081
1082 wl->ibss_starter = false;
1083
1084
1085 err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
76c06459 1086 if (unlikely(err)) {
69274f02
SS
1087 WL_ERR("WLC_SET_SSID failed (%d)\n", err);
1088 goto done;
cf2b4488 1089 }
69274f02
SS
1090
1091 set_bit(WL_STATUS_CONNECTING, &wl->status);
1092
1093done:
1ce4784e 1094 WL_TRACE("Exit\n");
cf2b4488
HP
1095 return err;
1096}
1097
3e26416e 1098static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
cf2b4488
HP
1099{
1100 struct wl_priv *wl = wiphy_to_wl(wiphy);
3e26416e 1101 s32 err = 0;
cf2b4488 1102
1ce4784e 1103 WL_TRACE("Enter\n");
cf2b4488 1104 CHECK_SYS_UP();
1ce4784e 1105
cf2b4488
HP
1106 wl_link_down(wl);
1107
1ce4784e
SS
1108 WL_TRACE("Exit\n");
1109
cf2b4488
HP
1110 return err;
1111}
1112
3e26416e 1113static s32
cf2b4488
HP
1114wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
1115{
1116 struct wl_priv *wl = ndev_to_wl(dev);
1117 struct wl_security *sec;
3e26416e
GKH
1118 s32 val = 0;
1119 s32 err = 0;
cf2b4488
HP
1120
1121 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1122 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1123 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1124 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1125 else
1126 val = WPA_AUTH_DISABLED;
1ce4784e 1127 WL_CONN("setting wpa_auth to 0x%0x\n", val);
76c06459
JC
1128 err = wl_dev_intvar_set(dev, "wpa_auth", val);
1129 if (unlikely(err)) {
f4528696 1130 WL_ERR("set wpa_auth failed (%d)\n", err);
cf2b4488
HP
1131 return err;
1132 }
1133 sec = wl_read_prof(wl, WL_PROF_SEC);
1134 sec->wpa_versions = sme->crypto.wpa_versions;
1135 return err;
1136}
1137
3e26416e 1138static s32
cf2b4488
HP
1139wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
1140{
1141 struct wl_priv *wl = ndev_to_wl(dev);
1142 struct wl_security *sec;
3e26416e
GKH
1143 s32 val = 0;
1144 s32 err = 0;
cf2b4488
HP
1145
1146 switch (sme->auth_type) {
1147 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1148 val = 0;
1ce4784e 1149 WL_CONN("open system\n");
cf2b4488
HP
1150 break;
1151 case NL80211_AUTHTYPE_SHARED_KEY:
1152 val = 1;
1ce4784e 1153 WL_CONN("shared key\n");
cf2b4488
HP
1154 break;
1155 case NL80211_AUTHTYPE_AUTOMATIC:
1156 val = 2;
1ce4784e 1157 WL_CONN("automatic\n");
cf2b4488
HP
1158 break;
1159 case NL80211_AUTHTYPE_NETWORK_EAP:
1ce4784e 1160 WL_CONN("network eap\n");
cf2b4488
HP
1161 default:
1162 val = 2;
f4528696 1163 WL_ERR("invalid auth type (%d)\n", sme->auth_type);
cf2b4488
HP
1164 break;
1165 }
1166
76c06459
JC
1167 err = wl_dev_intvar_set(dev, "auth", val);
1168 if (unlikely(err)) {
f4528696 1169 WL_ERR("set auth failed (%d)\n", err);
cf2b4488
HP
1170 return err;
1171 }
1172 sec = wl_read_prof(wl, WL_PROF_SEC);
1173 sec->auth_type = sme->auth_type;
1174 return err;
1175}
1176
3e26416e 1177static s32
cf2b4488
HP
1178wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
1179{
1180 struct wl_priv *wl = ndev_to_wl(dev);
1181 struct wl_security *sec;
3e26416e
GKH
1182 s32 pval = 0;
1183 s32 gval = 0;
1184 s32 err = 0;
cf2b4488
HP
1185
1186 if (sme->crypto.n_ciphers_pairwise) {
1187 switch (sme->crypto.ciphers_pairwise[0]) {
1188 case WLAN_CIPHER_SUITE_WEP40:
1189 case WLAN_CIPHER_SUITE_WEP104:
1190 pval = WEP_ENABLED;
1191 break;
1192 case WLAN_CIPHER_SUITE_TKIP:
1193 pval = TKIP_ENABLED;
1194 break;
1195 case WLAN_CIPHER_SUITE_CCMP:
1196 pval = AES_ENABLED;
1197 break;
1198 case WLAN_CIPHER_SUITE_AES_CMAC:
1199 pval = AES_ENABLED;
1200 break;
1201 default:
f4528696
JP
1202 WL_ERR("invalid cipher pairwise (%d)\n",
1203 sme->crypto.ciphers_pairwise[0]);
cf2b4488
HP
1204 return -EINVAL;
1205 }
1206 }
1207 if (sme->crypto.cipher_group) {
1208 switch (sme->crypto.cipher_group) {
1209 case WLAN_CIPHER_SUITE_WEP40:
1210 case WLAN_CIPHER_SUITE_WEP104:
1211 gval = WEP_ENABLED;
1212 break;
1213 case WLAN_CIPHER_SUITE_TKIP:
1214 gval = TKIP_ENABLED;
1215 break;
1216 case WLAN_CIPHER_SUITE_CCMP:
1217 gval = AES_ENABLED;
1218 break;
1219 case WLAN_CIPHER_SUITE_AES_CMAC:
1220 gval = AES_ENABLED;
1221 break;
1222 default:
f4528696
JP
1223 WL_ERR("invalid cipher group (%d)\n",
1224 sme->crypto.cipher_group);
cf2b4488
HP
1225 return -EINVAL;
1226 }
1227 }
1228
1ce4784e 1229 WL_CONN("pval (%d) gval (%d)\n", pval, gval);
76c06459
JC
1230 err = wl_dev_intvar_set(dev, "wsec", pval | gval);
1231 if (unlikely(err)) {
f4528696 1232 WL_ERR("error (%d)\n", err);
cf2b4488
HP
1233 return err;
1234 }
1235
1236 sec = wl_read_prof(wl, WL_PROF_SEC);
1237 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1238 sec->cipher_group = sme->crypto.cipher_group;
1239
1240 return err;
1241}
1242
3e26416e 1243static s32
cf2b4488
HP
1244wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
1245{
1246 struct wl_priv *wl = ndev_to_wl(dev);
1247 struct wl_security *sec;
3e26416e
GKH
1248 s32 val = 0;
1249 s32 err = 0;
cf2b4488
HP
1250
1251 if (sme->crypto.n_akm_suites) {
76c06459
JC
1252 err = wl_dev_intvar_get(dev, "wpa_auth", &val);
1253 if (unlikely(err)) {
f4528696 1254 WL_ERR("could not get wpa_auth (%d)\n", err);
cf2b4488
HP
1255 return err;
1256 }
1257 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1258 switch (sme->crypto.akm_suites[0]) {
1259 case WLAN_AKM_SUITE_8021X:
1260 val = WPA_AUTH_UNSPECIFIED;
1261 break;
1262 case WLAN_AKM_SUITE_PSK:
1263 val = WPA_AUTH_PSK;
1264 break;
1265 default:
f4528696
JP
1266 WL_ERR("invalid cipher group (%d)\n",
1267 sme->crypto.cipher_group);
cf2b4488
HP
1268 return -EINVAL;
1269 }
1270 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
1271 switch (sme->crypto.akm_suites[0]) {
1272 case WLAN_AKM_SUITE_8021X:
1273 val = WPA2_AUTH_UNSPECIFIED;
1274 break;
1275 case WLAN_AKM_SUITE_PSK:
1276 val = WPA2_AUTH_PSK;
1277 break;
1278 default:
f4528696
JP
1279 WL_ERR("invalid cipher group (%d)\n",
1280 sme->crypto.cipher_group);
cf2b4488
HP
1281 return -EINVAL;
1282 }
1283 }
1284
1ce4784e 1285 WL_CONN("setting wpa_auth to %d\n", val);
76c06459
JC
1286 err = wl_dev_intvar_set(dev, "wpa_auth", val);
1287 if (unlikely(err)) {
f4528696 1288 WL_ERR("could not set wpa_auth (%d)\n", err);
cf2b4488
HP
1289 return err;
1290 }
1291 }
1292 sec = wl_read_prof(wl, WL_PROF_SEC);
1293 sec->wpa_auth = sme->crypto.akm_suites[0];
1294
1295 return err;
1296}
1297
3e26416e 1298static s32
cf2b4488
HP
1299wl_set_set_sharedkey(struct net_device *dev,
1300 struct cfg80211_connect_params *sme)
1301{
1302 struct wl_priv *wl = ndev_to_wl(dev);
1303 struct wl_security *sec;
1304 struct wl_wsec_key key;
3e26416e
GKH
1305 s32 val;
1306 s32 err = 0;
cf2b4488 1307
1ce4784e 1308 WL_CONN("key len (%d)\n", sme->key_len);
cf2b4488
HP
1309 if (sme->key_len) {
1310 sec = wl_read_prof(wl, WL_PROF_SEC);
1ce4784e 1311 WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n",
f4528696 1312 sec->wpa_versions, sec->cipher_pairwise);
cf2b4488
HP
1313 if (!
1314 (sec->wpa_versions & (NL80211_WPA_VERSION_1 |
1315 NL80211_WPA_VERSION_2))
1316&& (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
1317 WLAN_CIPHER_SUITE_WEP104))) {
1318 memset(&key, 0, sizeof(key));
66cbd3ab
GKH
1319 key.len = (u32) sme->key_len;
1320 key.index = (u32) sme->key_idx;
cf2b4488 1321 if (unlikely(key.len > sizeof(key.data))) {
f4528696 1322 WL_ERR("Too long key length (%u)\n", key.len);
cf2b4488
HP
1323 return -EINVAL;
1324 }
1325 memcpy(key.data, sme->key, key.len);
1326 key.flags = WL_PRIMARY_KEY;
1327 switch (sec->cipher_pairwise) {
1328 case WLAN_CIPHER_SUITE_WEP40:
1329 key.algo = CRYPTO_ALGO_WEP1;
1330 break;
1331 case WLAN_CIPHER_SUITE_WEP104:
1332 key.algo = CRYPTO_ALGO_WEP128;
1333 break;
1334 default:
f4528696
JP
1335 WL_ERR("Invalid algorithm (%d)\n",
1336 sme->crypto.ciphers_pairwise[0]);
cf2b4488
HP
1337 return -EINVAL;
1338 }
1339 /* Set the new key/index */
1ce4784e 1340 WL_CONN("key length (%d) key index (%d) algo (%d)\n",
f4528696 1341 key.len, key.index, key.algo);
1ce4784e 1342 WL_CONN("key \"%s\"\n", key.data);
cf2b4488 1343 swap_key_from_BE(&key);
76c06459
JC
1344 err = wl_dev_ioctl(dev, WLC_SET_KEY, &key,
1345 sizeof(key));
1346 if (unlikely(err)) {
f4528696 1347 WL_ERR("WLC_SET_KEY error (%d)\n", err);
cf2b4488
HP
1348 return err;
1349 }
1350 if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
1ce4784e 1351 WL_CONN("set auth_type to shared key\n");
cf2b4488 1352 val = 1; /* shared key */
76c06459
JC
1353 err = wl_dev_intvar_set(dev, "auth", val);
1354 if (unlikely(err)) {
f4528696 1355 WL_ERR("set auth failed (%d)\n", err);
cf2b4488
HP
1356 return err;
1357 }
1358 }
1359 }
1360 }
1361 return err;
1362}
1363
3e26416e 1364static s32
cf2b4488
HP
1365wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
1366 struct cfg80211_connect_params *sme)
1367{
1368 struct wl_priv *wl = wiphy_to_wl(wiphy);
1369 struct ieee80211_channel *chan = sme->channel;
fb693a71 1370 struct wl_join_params join_params;
1371 size_t join_params_size;
1372
3e26416e 1373 s32 err = 0;
cf2b4488 1374
1ce4784e 1375 WL_TRACE("Enter\n");
cf2b4488 1376 CHECK_SYS_UP();
1ce4784e 1377
cf2b4488 1378 if (unlikely(!sme->ssid)) {
f4528696 1379 WL_ERR("Invalid ssid\n");
cf2b4488
HP
1380 return -EOPNOTSUPP;
1381 }
1ce4784e 1382
cf2b4488 1383 if (chan) {
e494632e
SS
1384 wl->channel =
1385 ieee80211_frequency_to_channel(chan->center_freq);
1ce4784e 1386 WL_CONN("channel (%d), center_req (%d)\n",
e494632e
SS
1387 wl->channel, chan->center_freq);
1388 } else
1389 wl->channel = 0;
1ce4784e
SS
1390
1391 WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1392
76c06459
JC
1393 err = wl_set_wpa_version(dev, sme);
1394 if (unlikely(err))
cf2b4488
HP
1395 return err;
1396
76c06459
JC
1397 err = wl_set_auth_type(dev, sme);
1398 if (unlikely(err))
cf2b4488
HP
1399 return err;
1400
76c06459
JC
1401 err = wl_set_set_cipher(dev, sme);
1402 if (unlikely(err))
cf2b4488
HP
1403 return err;
1404
76c06459
JC
1405 err = wl_set_key_mgmt(dev, sme);
1406 if (unlikely(err))
cf2b4488
HP
1407 return err;
1408
76c06459
JC
1409 err = wl_set_set_sharedkey(dev, sme);
1410 if (unlikely(err))
cf2b4488
HP
1411 return err;
1412
1413 wl_update_prof(wl, NULL, sme->bssid, WL_PROF_BSSID);
1414 /*
1415 ** Join with specific BSSID and cached SSID
1416 ** If SSID is zero join based on BSSID only
1417 */
fb693a71 1418 memset(&join_params, 0, sizeof(join_params));
1419 join_params_size = sizeof(join_params.ssid);
1420
1421 join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
1422 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
29750b90 1423 join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
fb693a71 1424 wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
fb693a71 1425
e494632e
SS
1426 if (sme->bssid)
1427 memcpy(join_params.params.bssid, sme->bssid, ETH_ALEN);
1428 else
1429 memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
fb693a71 1430
1431 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1ce4784e 1432 WL_CONN("ssid \"%s\", len (%d)\n",
f4528696 1433 join_params.ssid.SSID, join_params.ssid.SSID_len);
fb693a71 1434 }
e494632e
SS
1435
1436 wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
fb693a71 1437 err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
76c06459 1438 if (unlikely(err)) {
f4528696 1439 WL_ERR("error (%d)\n", err);
cf2b4488
HP
1440 return err;
1441 }
1442 set_bit(WL_STATUS_CONNECTING, &wl->status);
1443
1ce4784e 1444 WL_TRACE("Exit\n");
cf2b4488
HP
1445 return err;
1446}
1447
3e26416e 1448static s32
cf2b4488 1449wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
7d4df48e 1450 u16 reason_code)
cf2b4488
HP
1451{
1452 struct wl_priv *wl = wiphy_to_wl(wiphy);
1453 scb_val_t scbval;
3e26416e 1454 s32 err = 0;
cf2b4488 1455
1ce4784e 1456 WL_TRACE("Enter. Reason code = %d\n", reason_code);
cf2b4488 1457 CHECK_SYS_UP();
e494632e
SS
1458
1459 clear_bit(WL_STATUS_CONNECTED, &wl->status);
1460
1461 scbval.val = reason_code;
1462 memcpy(&scbval.ea, wl_read_prof(wl, WL_PROF_BSSID), ETH_ALEN);
1463 scbval.val = cpu_to_le32(scbval.val);
1464 err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
1465 sizeof(scb_val_t));
1466 if (unlikely(err))
1467 WL_ERR("error (%d)\n", err);
1468
1469 wl->link_up = false;
cf2b4488 1470
1ce4784e 1471 WL_TRACE("Exit\n");
cf2b4488
HP
1472 return err;
1473}
1474
3e26416e 1475static s32
cf2b4488 1476wl_cfg80211_set_tx_power(struct wiphy *wiphy,
3e26416e 1477 enum nl80211_tx_power_setting type, s32 dbm)
cf2b4488
HP
1478{
1479
1480 struct wl_priv *wl = wiphy_to_wl(wiphy);
1481 struct net_device *ndev = wl_to_ndev(wl);
7d4df48e 1482 u16 txpwrmw;
3e26416e
GKH
1483 s32 err = 0;
1484 s32 disable = 0;
cf2b4488 1485
1ce4784e 1486 WL_TRACE("Enter\n");
cf2b4488 1487 CHECK_SYS_UP();
1ce4784e 1488
cf2b4488
HP
1489 switch (type) {
1490 case NL80211_TX_POWER_AUTOMATIC:
1491 break;
1492 case NL80211_TX_POWER_LIMITED:
1493 if (dbm < 0) {
f4528696 1494 WL_ERR("TX_POWER_LIMITED - dbm is negative\n");
1ce4784e
SS
1495 err = -EINVAL;
1496 goto done;
cf2b4488
HP
1497 }
1498 break;
1499 case NL80211_TX_POWER_FIXED:
1500 if (dbm < 0) {
f4528696 1501 WL_ERR("TX_POWER_FIXED - dbm is negative\n");
1ce4784e
SS
1502 err = -EINVAL;
1503 goto done;
cf2b4488
HP
1504 }
1505 break;
1506 }
1507 /* Make sure radio is off or on as far as software is concerned */
1508 disable = WL_RADIO_SW_DISABLE << 16;
29750b90 1509 disable = cpu_to_le32(disable);
76c06459 1510 err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable));
1ce4784e 1511 if (unlikely(err))
f4528696 1512 WL_ERR("WLC_SET_RADIO error (%d)\n", err);
cf2b4488
HP
1513
1514 if (dbm > 0xffff)
1515 txpwrmw = 0xffff;
1516 else
7d4df48e 1517 txpwrmw = (u16) dbm;
76c06459 1518 err = wl_dev_intvar_set(ndev, "qtxpower",
3e26416e 1519 (s32) (bcm_mw_to_qdbm(txpwrmw)));
1ce4784e 1520 if (unlikely(err))
f4528696 1521 WL_ERR("qtxpower error (%d)\n", err);
cf2b4488
HP
1522 wl->conf->tx_power = dbm;
1523
1ce4784e
SS
1524done:
1525 WL_TRACE("Exit\n");
cf2b4488
HP
1526 return err;
1527}
1528
3e26416e 1529static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
cf2b4488
HP
1530{
1531 struct wl_priv *wl = wiphy_to_wl(wiphy);
1532 struct net_device *ndev = wl_to_ndev(wl);
3e26416e 1533 s32 txpwrdbm;
3fd79f7c 1534 u8 result;
3e26416e 1535 s32 err = 0;
cf2b4488 1536
1ce4784e 1537 WL_TRACE("Enter\n");
cf2b4488 1538 CHECK_SYS_UP();
1ce4784e 1539
76c06459
JC
1540 err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
1541 if (unlikely(err)) {
f4528696 1542 WL_ERR("error (%d)\n", err);
1ce4784e 1543 goto done;
cf2b4488 1544 }
1ce4784e 1545
3fd79f7c 1546 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
3e26416e 1547 *dbm = (s32) bcm_qdbm_to_mw(result);
cf2b4488 1548
1ce4784e
SS
1549done:
1550 WL_TRACE("Exit\n");
cf2b4488
HP
1551 return err;
1552}
1553
3e26416e 1554static s32
cf2b4488 1555wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
8a6257fb 1556 u8 key_idx, bool unicast, bool multicast)
cf2b4488 1557{
66cbd3ab 1558 u32 index;
3e26416e
GKH
1559 s32 wsec;
1560 s32 err = 0;
cf2b4488 1561
1ce4784e
SS
1562 WL_TRACE("Enter\n");
1563 WL_CONN("key index (%d)\n", key_idx);
cf2b4488
HP
1564 CHECK_SYS_UP();
1565
76c06459
JC
1566 err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
1567 if (unlikely(err)) {
f4528696 1568 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1ce4784e 1569 goto done;
cf2b4488 1570 }
1ce4784e 1571
29750b90 1572 wsec = le32_to_cpu(wsec);
cf2b4488
HP
1573 if (wsec & WEP_ENABLED) {
1574 /* Just select a new current key */
66cbd3ab 1575 index = (u32) key_idx;
29750b90 1576 index = cpu_to_le32(index);
76c06459
JC
1577 err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
1578 sizeof(index));
1ce4784e 1579 if (unlikely(err))
f4528696 1580 WL_ERR("error (%d)\n", err);
cf2b4488 1581 }
1ce4784e
SS
1582done:
1583 WL_TRACE("Exit\n");
cf2b4488
HP
1584 return err;
1585}
1586
3e26416e 1587static s32
cf2b4488 1588wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
3fd79f7c 1589 u8 key_idx, const u8 *mac_addr, struct key_params *params)
cf2b4488
HP
1590{
1591 struct wl_wsec_key key;
3e26416e 1592 s32 err = 0;
cf2b4488
HP
1593
1594 memset(&key, 0, sizeof(key));
66cbd3ab 1595 key.index = (u32) key_idx;
cf2b4488
HP
1596 /* Instead of bcast for ea address for default wep keys,
1597 driver needs it to be Null */
3ca5ada5 1598 if (!is_multicast_ether_addr(mac_addr))
b8d63078 1599 memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
66cbd3ab 1600 key.len = (u32) params->key_len;
cf2b4488
HP
1601 /* check for key index change */
1602 if (key.len == 0) {
1603 /* key delete */
1604 swap_key_from_BE(&key);
76c06459
JC
1605 err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
1606 if (unlikely(err)) {
f4528696 1607 WL_ERR("key delete error (%d)\n", err);
cf2b4488
HP
1608 return err;
1609 }
1610 } else {
1611 if (key.len > sizeof(key.data)) {
f4528696 1612 WL_ERR("Invalid key length (%d)\n", key.len);
cf2b4488
HP
1613 return -EINVAL;
1614 }
1615
1ce4784e 1616 WL_CONN("Setting the key index %d\n", key.index);
cf2b4488
HP
1617 memcpy(key.data, params->key, key.len);
1618
1619 if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
3fd79f7c 1620 u8 keybuf[8];
cf2b4488
HP
1621 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1622 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1623 memcpy(&key.data[16], keybuf, sizeof(keybuf));
1624 }
1625
1626 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
1627 if (params->seq && params->seq_len == 6) {
1628 /* rx iv */
3fd79f7c
GKH
1629 u8 *ivptr;
1630 ivptr = (u8 *) params->seq;
cf2b4488
HP
1631 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1632 (ivptr[3] << 8) | ivptr[2];
1633 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
0f0881b0 1634 key.iv_initialized = true;
cf2b4488
HP
1635 }
1636
1637 switch (params->cipher) {
1638 case WLAN_CIPHER_SUITE_WEP40:
1639 key.algo = CRYPTO_ALGO_WEP1;
1ce4784e 1640 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
cf2b4488
HP
1641 break;
1642 case WLAN_CIPHER_SUITE_WEP104:
1643 key.algo = CRYPTO_ALGO_WEP128;
1ce4784e 1644 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
cf2b4488
HP
1645 break;
1646 case WLAN_CIPHER_SUITE_TKIP:
1647 key.algo = CRYPTO_ALGO_TKIP;
1ce4784e 1648 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
cf2b4488
HP
1649 break;
1650 case WLAN_CIPHER_SUITE_AES_CMAC:
1651 key.algo = CRYPTO_ALGO_AES_CCM;
1ce4784e 1652 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
cf2b4488
HP
1653 break;
1654 case WLAN_CIPHER_SUITE_CCMP:
1655 key.algo = CRYPTO_ALGO_AES_CCM;
1ce4784e 1656 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
cf2b4488
HP
1657 break;
1658 default:
f4528696 1659 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
cf2b4488
HP
1660 return -EINVAL;
1661 }
1662 swap_key_from_BE(&key);
1663
1664 dhd_wait_pend8021x(dev);
76c06459
JC
1665 err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
1666 if (unlikely(err)) {
f4528696 1667 WL_ERR("WLC_SET_KEY error (%d)\n", err);
cf2b4488
HP
1668 return err;
1669 }
1670 }
1671 return err;
1672}
1673
3e26416e 1674static s32
cf2b4488 1675wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
34a488c1 1676 u8 key_idx, bool pairwise, const u8 *mac_addr,
cf2b4488
HP
1677 struct key_params *params)
1678{
1679 struct wl_wsec_key key;
3e26416e
GKH
1680 s32 val;
1681 s32 wsec;
1682 s32 err = 0;
22d5d59b 1683 u8 keybuf[8];
cf2b4488 1684
1ce4784e
SS
1685 WL_TRACE("Enter\n");
1686 WL_CONN("key index (%d)\n", key_idx);
cf2b4488
HP
1687 CHECK_SYS_UP();
1688
1ce4784e
SS
1689 if (mac_addr) {
1690 WL_TRACE("Exit");
cf2b4488 1691 return wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
1ce4784e 1692 }
cf2b4488
HP
1693 memset(&key, 0, sizeof(key));
1694
66cbd3ab
GKH
1695 key.len = (u32) params->key_len;
1696 key.index = (u32) key_idx;
cf2b4488
HP
1697
1698 if (unlikely(key.len > sizeof(key.data))) {
f4528696 1699 WL_ERR("Too long key length (%u)\n", key.len);
1ce4784e
SS
1700 err = -EINVAL;
1701 goto done;
cf2b4488
HP
1702 }
1703 memcpy(key.data, params->key, key.len);
1704
1705 key.flags = WL_PRIMARY_KEY;
1706 switch (params->cipher) {
1707 case WLAN_CIPHER_SUITE_WEP40:
1708 key.algo = CRYPTO_ALGO_WEP1;
1ce4784e 1709 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
cf2b4488
HP
1710 break;
1711 case WLAN_CIPHER_SUITE_WEP104:
1712 key.algo = CRYPTO_ALGO_WEP128;
1ce4784e 1713 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
cf2b4488
HP
1714 break;
1715 case WLAN_CIPHER_SUITE_TKIP:
22d5d59b
SS
1716 memcpy(keybuf, &key.data[24], sizeof(keybuf));
1717 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
1718 memcpy(&key.data[16], keybuf, sizeof(keybuf));
cf2b4488 1719 key.algo = CRYPTO_ALGO_TKIP;
1ce4784e 1720 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
cf2b4488
HP
1721 break;
1722 case WLAN_CIPHER_SUITE_AES_CMAC:
1723 key.algo = CRYPTO_ALGO_AES_CCM;
1ce4784e 1724 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
cf2b4488
HP
1725 break;
1726 case WLAN_CIPHER_SUITE_CCMP:
1727 key.algo = CRYPTO_ALGO_AES_CCM;
1ce4784e 1728 WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
cf2b4488
HP
1729 break;
1730 default:
f4528696 1731 WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
1ce4784e
SS
1732 err = -EINVAL;
1733 goto done;
cf2b4488
HP
1734 }
1735
1736 /* Set the new key/index */
1737 swap_key_from_BE(&key);
76c06459
JC
1738 err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
1739 if (unlikely(err)) {
f4528696 1740 WL_ERR("WLC_SET_KEY error (%d)\n", err);
1ce4784e 1741 goto done;
cf2b4488
HP
1742 }
1743
1744 val = WEP_ENABLED;
76c06459
JC
1745 err = wl_dev_intvar_get(dev, "wsec", &wsec);
1746 if (unlikely(err)) {
f4528696 1747 WL_ERR("get wsec error (%d)\n", err);
1ce4784e 1748 goto done;
cf2b4488
HP
1749 }
1750 wsec &= ~(WEP_ENABLED);
1751 wsec |= val;
76c06459
JC
1752 err = wl_dev_intvar_set(dev, "wsec", wsec);
1753 if (unlikely(err)) {
f4528696 1754 WL_ERR("set wsec error (%d)\n", err);
1ce4784e 1755 goto done;
cf2b4488
HP
1756 }
1757
1758 val = 1; /* assume shared key. otherwise 0 */
29750b90 1759 val = cpu_to_le32(val);
76c06459 1760 err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
1ce4784e 1761 if (unlikely(err))
f4528696 1762 WL_ERR("WLC_SET_AUTH error (%d)\n", err);
1ce4784e
SS
1763done:
1764 WL_TRACE("Exit\n");
cf2b4488
HP
1765 return err;
1766}
1767
3e26416e 1768static s32
cf2b4488 1769wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
34a488c1 1770 u8 key_idx, bool pairwise, const u8 *mac_addr)
cf2b4488
HP
1771{
1772 struct wl_wsec_key key;
3e26416e
GKH
1773 s32 err = 0;
1774 s32 val;
1775 s32 wsec;
cf2b4488 1776
1ce4784e 1777 WL_TRACE("Enter\n");
cf2b4488
HP
1778 CHECK_SYS_UP();
1779 memset(&key, 0, sizeof(key));
1780
66cbd3ab 1781 key.index = (u32) key_idx;
cf2b4488
HP
1782 key.flags = WL_PRIMARY_KEY;
1783 key.algo = CRYPTO_ALGO_OFF;
1784
1ce4784e 1785 WL_CONN("key index (%d)\n", key_idx);
cf2b4488
HP
1786 /* Set the new key/index */
1787 swap_key_from_BE(&key);
76c06459
JC
1788 err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
1789 if (unlikely(err)) {
cf2b4488 1790 if (err == -EINVAL) {
1ce4784e 1791 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
cf2b4488 1792 /* we ignore this key index in this case */
1ce4784e
SS
1793 WL_ERR("invalid key index (%d)\n", key_idx);
1794 } else
f4528696 1795 WL_ERR("WLC_SET_KEY error (%d)\n", err);
1ce4784e
SS
1796
1797 /* Ignore this error, may happen during DISASSOC */
1798 err = -EAGAIN;
1799 goto done;
cf2b4488
HP
1800 }
1801
1802 val = 0;
76c06459
JC
1803 err = wl_dev_intvar_get(dev, "wsec", &wsec);
1804 if (unlikely(err)) {
f4528696 1805 WL_ERR("get wsec error (%d)\n", err);
1ce4784e
SS
1806 /* Ignore this error, may happen during DISASSOC */
1807 err = -EAGAIN;
1808 goto done;
cf2b4488
HP
1809 }
1810 wsec &= ~(WEP_ENABLED);
1811 wsec |= val;
76c06459
JC
1812 err = wl_dev_intvar_set(dev, "wsec", wsec);
1813 if (unlikely(err)) {
f4528696 1814 WL_ERR("set wsec error (%d)\n", err);
1ce4784e
SS
1815 /* Ignore this error, may happen during DISASSOC */
1816 err = -EAGAIN;
1817 goto done;
cf2b4488
HP
1818 }
1819
1820 val = 0; /* assume open key. otherwise 1 */
29750b90 1821 val = cpu_to_le32(val);
76c06459
JC
1822 err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
1823 if (unlikely(err)) {
f4528696 1824 WL_ERR("WLC_SET_AUTH error (%d)\n", err);
1ce4784e
SS
1825 /* Ignore this error, may happen during DISASSOC */
1826 err = -EAGAIN;
cf2b4488 1827 }
1ce4784e
SS
1828done:
1829 WL_TRACE("Exit\n");
cf2b4488
HP
1830 return err;
1831}
1832
3e26416e 1833static s32
cf2b4488 1834wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
34a488c1 1835 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
cf2b4488
HP
1836 void (*callback) (void *cookie, struct key_params * params))
1837{
1838 struct key_params params;
1839 struct wl_wsec_key key;
1840 struct wl_priv *wl = wiphy_to_wl(wiphy);
1841 struct wl_security *sec;
3e26416e
GKH
1842 s32 wsec;
1843 s32 err = 0;
cf2b4488 1844
1ce4784e
SS
1845 WL_TRACE("Enter\n");
1846 WL_CONN("key index (%d)\n", key_idx);
cf2b4488
HP
1847 CHECK_SYS_UP();
1848
1849 memset(&key, 0, sizeof(key));
1850 key.index = key_idx;
1851 swap_key_to_BE(&key);
1852 memset(&params, 0, sizeof(params));
f4728c38 1853 params.key_len = (u8) min_t(u8, WLAN_MAX_KEY_LEN, key.len);
cf2b4488
HP
1854 memcpy(params.key, key.data, params.key_len);
1855
76c06459
JC
1856 err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
1857 if (unlikely(err)) {
f4528696 1858 WL_ERR("WLC_GET_WSEC error (%d)\n", err);
1ce4784e
SS
1859 /* Ignore this error, may happen during DISASSOC */
1860 err = -EAGAIN;
1861 goto done;
cf2b4488 1862 }
29750b90 1863 wsec = le32_to_cpu(wsec);
cf2b4488
HP
1864 switch (wsec) {
1865 case WEP_ENABLED:
1866 sec = wl_read_prof(wl, WL_PROF_SEC);
1867 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
1868 params.cipher = WLAN_CIPHER_SUITE_WEP40;
1ce4784e 1869 WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
cf2b4488
HP
1870 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
1871 params.cipher = WLAN_CIPHER_SUITE_WEP104;
1ce4784e 1872 WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
cf2b4488
HP
1873 }
1874 break;
1875 case TKIP_ENABLED:
1876 params.cipher = WLAN_CIPHER_SUITE_TKIP;
1ce4784e 1877 WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
cf2b4488
HP
1878 break;
1879 case AES_ENABLED:
1880 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
1ce4784e 1881 WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
cf2b4488
HP
1882 break;
1883 default:
f4528696 1884 WL_ERR("Invalid algo (0x%x)\n", wsec);
1ce4784e
SS
1885 err = -EINVAL;
1886 goto done;
cf2b4488 1887 }
cf2b4488 1888 callback(cookie, &params);
1ce4784e
SS
1889
1890done:
1891 WL_TRACE("Exit\n");
cf2b4488
HP
1892 return err;
1893}
1894
3e26416e 1895static s32
cf2b4488 1896wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
3fd79f7c 1897 struct net_device *dev, u8 key_idx)
cf2b4488 1898{
f4528696 1899 WL_INFO("Not supported\n");
1ce4784e 1900
cf2b4488
HP
1901 CHECK_SYS_UP();
1902 return -EOPNOTSUPP;
1903}
1904
3e26416e 1905static s32
cf2b4488 1906wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
3fd79f7c 1907 u8 *mac, struct station_info *sinfo)
cf2b4488
HP
1908{
1909 struct wl_priv *wl = wiphy_to_wl(wiphy);
1910 scb_val_t scb_val;
1911 int rssi;
3e26416e
GKH
1912 s32 rate;
1913 s32 err = 0;
1ce4784e 1914 u8 *bssid = wl_read_prof(wl, WL_PROF_BSSID);
cf2b4488 1915
1ce4784e 1916 WL_TRACE("Enter\n");
cf2b4488 1917 CHECK_SYS_UP();
1ce4784e 1918
cf2b4488 1919 if (unlikely
1ce4784e
SS
1920 (memcmp(mac, bssid, ETH_ALEN))) {
1921 WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X"
1922 "wl_bssid-%X:%X:%X:%X:%X:%X\n",
1923 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
1924 bssid[0], bssid[1], bssid[2], bssid[3],
1925 bssid[4], bssid[5]);
1926 err = -ENOENT;
1927 goto done;
cf2b4488
HP
1928 }
1929
1930 /* Report the current tx rate */
76c06459
JC
1931 err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
1932 if (err) {
f4528696 1933 WL_ERR("Could not get rate (%d)\n", err);
cf2b4488 1934 } else {
29750b90 1935 rate = le32_to_cpu(rate);
cf2b4488
HP
1936 sinfo->filled |= STATION_INFO_TX_BITRATE;
1937 sinfo->txrate.legacy = rate * 5;
1ce4784e 1938 WL_CONN("Rate %d Mbps\n", rate / 2);
cf2b4488
HP
1939 }
1940
1941 if (test_bit(WL_STATUS_CONNECTED, &wl->status)) {
1942 scb_val.val = 0;
76c06459
JC
1943 err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val,
1944 sizeof(scb_val_t));
1945 if (unlikely(err)) {
f4528696 1946 WL_ERR("Could not get rssi (%d)\n", err);
cf2b4488 1947 }
29750b90 1948 rssi = le32_to_cpu(scb_val.val);
cf2b4488
HP
1949 sinfo->filled |= STATION_INFO_SIGNAL;
1950 sinfo->signal = rssi;
1ce4784e 1951 WL_CONN("RSSI %d dBm\n", rssi);
cf2b4488
HP
1952 }
1953
1ce4784e
SS
1954done:
1955 WL_TRACE("Exit\n");
cf2b4488
HP
1956 return err;
1957}
1958
3e26416e 1959static s32
cf2b4488 1960wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
3e26416e 1961 bool enabled, s32 timeout)
cf2b4488 1962{
3e26416e
GKH
1963 s32 pm;
1964 s32 err = 0;
cf2b4488 1965
1ce4784e 1966 WL_TRACE("Enter\n");
cf2b4488 1967 CHECK_SYS_UP();
1ce4784e 1968
cf2b4488 1969 pm = enabled ? PM_FAST : PM_OFF;
29750b90 1970 pm = cpu_to_le32(pm);
1ce4784e
SS
1971 WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
1972
76c06459
JC
1973 err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
1974 if (unlikely(err)) {
cf2b4488 1975 if (err == -ENODEV)
1ce4784e 1976 WL_ERR("net_device is not ready yet\n");
cf2b4488 1977 else
f4528696 1978 WL_ERR("error (%d)\n", err);
cf2b4488 1979 }
1ce4784e 1980 WL_TRACE("Exit\n");
cf2b4488
HP
1981 return err;
1982}
1983
66cbd3ab 1984static __used u32 wl_find_msb(u16 bit16)
cf2b4488 1985{
66cbd3ab 1986 u32 ret = 0;
cf2b4488
HP
1987
1988 if (bit16 & 0xff00) {
1989 ret += 8;
1990 bit16 >>= 8;
1991 }
1992
1993 if (bit16 & 0xf0) {
1994 ret += 4;
1995 bit16 >>= 4;
1996 }
1997
1998 if (bit16 & 0xc) {
1999 ret += 2;
2000 bit16 >>= 2;
2001 }
2002
2003 if (bit16 & 2)
2004 ret += bit16 & 2;
2005 else if (bit16)
2006 ret += bit16;
2007
2008 return ret;
2009}
2010
3e26416e 2011static s32
cf2b4488 2012wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
3fd79f7c 2013 const u8 *addr,
cf2b4488
HP
2014 const struct cfg80211_bitrate_mask *mask)
2015{
2016 struct wl_rateset rateset;
3e26416e
GKH
2017 s32 rate;
2018 s32 val;
2019 s32 err_bg;
2020 s32 err_a;
66cbd3ab 2021 u32 legacy;
3e26416e 2022 s32 err = 0;
cf2b4488 2023
1ce4784e 2024 WL_TRACE("Enter\n");
cf2b4488 2025 CHECK_SYS_UP();
1ce4784e 2026
cf2b4488
HP
2027 /* addr param is always NULL. ignore it */
2028 /* Get current rateset */
76c06459
JC
2029 err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
2030 sizeof(rateset));
2031 if (unlikely(err)) {
f4528696 2032 WL_ERR("could not get current rateset (%d)\n", err);
1ce4784e 2033 goto done;
cf2b4488
HP
2034 }
2035
29750b90 2036 rateset.count = le32_to_cpu(rateset.count);
cf2b4488 2037
76c06459
JC
2038 legacy = wl_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy);
2039 if (!legacy)
cf2b4488
HP
2040 legacy = wl_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy);
2041
2042 val = wl_g_rates[legacy - 1].bitrate * 100000;
2043
1ce4784e 2044 if (val < rateset.count)
cf2b4488
HP
2045 /* Select rate by rateset index */
2046 rate = rateset.rates[val] & 0x7f;
1ce4784e 2047 else
cf2b4488
HP
2048 /* Specified rate in bps */
2049 rate = val / 500000;
cf2b4488 2050
1ce4784e 2051 WL_CONN("rate %d mbps\n", rate / 2);
cf2b4488
HP
2052
2053 /*
2054 *
2055 * Set rate override,
2056 * Since the is a/b/g-blind, both a/bg_rate are enforced.
2057 */
2058 err_bg = wl_dev_intvar_set(dev, "bg_rate", rate);
2059 err_a = wl_dev_intvar_set(dev, "a_rate", rate);
2060 if (unlikely(err_bg && err_a)) {
f4528696 2061 WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
1ce4784e 2062 err = err_bg | err_a;
cf2b4488
HP
2063 }
2064
1ce4784e
SS
2065done:
2066 WL_TRACE("Exit\n");
cf2b4488
HP
2067 return err;
2068}
2069
3e26416e 2070static s32 wl_cfg80211_resume(struct wiphy *wiphy)
cf2b4488 2071{
e6e8f894
SS
2072 struct wl_priv *wl = wiphy_to_wl(wiphy);
2073 struct net_device *ndev = wl_to_ndev(wl);
cf2b4488 2074
e6e8f894
SS
2075 /*
2076 * Check for WL_STATUS_READY before any function call which
2077 * could result is bus access. Don't block the resume for
2078 * any driver error conditions
2079 */
1ce4784e 2080 WL_TRACE("Enter\n");
cf2b4488 2081
e6e8f894
SS
2082#if defined(CONFIG_PM_SLEEP)
2083 atomic_set(&dhd_mmc_suspend, false);
2084#endif /* defined(CONFIG_PM_SLEEP) */
2085
2086 if (test_bit(WL_STATUS_READY, &wl->status)) {
2087 /* Turn on Watchdog timer */
2088 wl_os_wd_timer(ndev, dhd_watchdog_ms);
2089 wl_invoke_iscan(wiphy_to_wl(wiphy));
2090 }
2091
1ce4784e 2092 WL_TRACE("Exit\n");
e6e8f894 2093 return 0;
cf2b4488
HP
2094}
2095
3e26416e 2096static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
cf2b4488
HP
2097{
2098 struct wl_priv *wl = wiphy_to_wl(wiphy);
fb693a71 2099 struct net_device *ndev = wl_to_ndev(wl);
e6e8f894 2100
1ce4784e 2101 WL_TRACE("Enter\n");
e6e8f894
SS
2102
2103 /*
2104 * Check for WL_STATUS_READY before any function call which
2105 * could result is bus access. Don't block the suspend for
2106 * any driver error conditions
2107 */
2108
2109 /*
2110 * While going to suspend if associated with AP disassociate
2111 * from AP to save power while system is in suspended state
2112 */
2113 if (test_bit(WL_STATUS_CONNECTED, &wl->status) &&
2114 test_bit(WL_STATUS_READY, &wl->status)) {
2115 WL_INFO("Disassociating from AP"
2116 " while entering suspend state\n");
2117 wl_link_down(wl);
2118
2119 /*
2120 * Make sure WPA_Supplicant receives all the event
2121 * generated due to DISASSOC call to the fw to keep
2122 * the state fw and WPA_Supplicant state consistent
2123 */
2124 rtnl_unlock();
2125 wl_delay(500);
2126 rtnl_lock();
2127 }
cf2b4488 2128
cf2b4488 2129 set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
e6e8f894
SS
2130 if (test_bit(WL_STATUS_READY, &wl->status))
2131 wl_term_iscan(wl);
2132
cf2b4488 2133 if (wl->scan_request) {
e6e8f894
SS
2134 /* Indidate scan abort to cfg80211 layer */
2135 WL_INFO("Terminating scan in progress\n");
2136 cfg80211_scan_done(wl->scan_request, true);
cf2b4488
HP
2137 wl->scan_request = NULL;
2138 }
2139 clear_bit(WL_STATUS_SCANNING, &wl->status);
2140 clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
e6e8f894
SS
2141 clear_bit(WL_STATUS_CONNECTING, &wl->status);
2142 clear_bit(WL_STATUS_CONNECTED, &wl->status);
6b5a5a3e 2143
e6e8f894 2144 /* Inform SDIO stack not to switch off power to the chip */
6b5a5a3e 2145 sdioh_sdio_set_host_pm_flags(MMC_PM_KEEP_POWER);
cf2b4488 2146
e6e8f894
SS
2147 /* Turn off watchdog timer */
2148 if (test_bit(WL_STATUS_READY, &wl->status)) {
2149 WL_INFO("Terminate watchdog timer and enable MPC\n");
2150 wl_set_mpc(ndev, 1);
2151 wl_os_wd_timer(ndev, 0);
2152 }
2153
2154#if defined(CONFIG_PM_SLEEP)
2155 atomic_set(&dhd_mmc_suspend, true);
2156#endif /* defined(CONFIG_PM_SLEEP) */
2157
1ce4784e 2158 WL_TRACE("Exit\n");
e6e8f894
SS
2159
2160 return 0;
cf2b4488
HP
2161}
2162
3e26416e 2163static __used s32
cf2b4488 2164wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
3e26416e 2165 s32 err)
cf2b4488 2166{
cf2b4488
HP
2167 int i, j;
2168
1ce4784e 2169 WL_CONN("No of elements %d\n", pmk_list->pmkids.npmkid);
cf2b4488 2170 for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
1ce4784e 2171 WL_CONN("PMKID[%d]: %pM =\n", i,
35af8764 2172 &pmk_list->pmkids.pmkid[i].BSSID);
1ce4784e
SS
2173 for (j = 0; j < WLAN_PMKID_LEN; j++)
2174 WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
cf2b4488 2175 }
1ce4784e
SS
2176
2177 if (likely(!err))
2178 wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
cf2b4488 2179 sizeof(*pmk_list));
cf2b4488
HP
2180
2181 return err;
2182}
2183
3e26416e 2184static s32
cf2b4488
HP
2185wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
2186 struct cfg80211_pmksa *pmksa)
2187{
2188 struct wl_priv *wl = wiphy_to_wl(wiphy);
3e26416e 2189 s32 err = 0;
cf2b4488
HP
2190 int i;
2191
1ce4784e 2192 WL_TRACE("Enter\n");
cf2b4488 2193 CHECK_SYS_UP();
1ce4784e 2194
cf2b4488
HP
2195 for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
2196 if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
b8d63078 2197 ETH_ALEN))
cf2b4488
HP
2198 break;
2199 if (i < WL_NUM_PMKIDS_MAX) {
2200 memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
b8d63078 2201 ETH_ALEN);
cf2b4488 2202 memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
35af8764 2203 WLAN_PMKID_LEN);
cf2b4488
HP
2204 if (i == wl->pmk_list->pmkids.npmkid)
2205 wl->pmk_list->pmkids.npmkid++;
1ce4784e 2206 } else
cf2b4488 2207 err = -EINVAL;
1ce4784e
SS
2208
2209 WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
f4528696 2210 &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID);
1ce4784e
SS
2211 for (i = 0; i < WLAN_PMKID_LEN; i++)
2212 WL_CONN("%02x\n",
f4528696
JP
2213 wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].
2214 PMKID[i]);
cf2b4488
HP
2215
2216 err = wl_update_pmklist(dev, wl->pmk_list, err);
2217
1ce4784e 2218 WL_TRACE("Exit\n");
cf2b4488
HP
2219 return err;
2220}
2221
3e26416e 2222static s32
cf2b4488
HP
2223wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
2224 struct cfg80211_pmksa *pmksa)
2225{
2226 struct wl_priv *wl = wiphy_to_wl(wiphy);
cf2b4488 2227 struct _pmkid_list pmkid;
3e26416e 2228 s32 err = 0;
cf2b4488
HP
2229 int i;
2230
1ce4784e 2231 WL_TRACE("Enter\n");
cf2b4488 2232 CHECK_SYS_UP();
b8d63078 2233 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
35af8764 2234 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
cf2b4488 2235
1ce4784e 2236 WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
f4528696 2237 &pmkid.pmkid[0].BSSID);
1ce4784e
SS
2238 for (i = 0; i < WLAN_PMKID_LEN; i++)
2239 WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
cf2b4488
HP
2240
2241 for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
2242 if (!memcmp
2243 (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
b8d63078 2244 ETH_ALEN))
cf2b4488
HP
2245 break;
2246
2247 if ((wl->pmk_list->pmkids.npmkid > 0)
2248 && (i < wl->pmk_list->pmkids.npmkid)) {
2249 memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
2250 for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) {
2251 memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID,
2252 &wl->pmk_list->pmkids.pmkid[i + 1].BSSID,
b8d63078 2253 ETH_ALEN);
cf2b4488
HP
2254 memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID,
2255 &wl->pmk_list->pmkids.pmkid[i + 1].PMKID,
35af8764 2256 WLAN_PMKID_LEN);
cf2b4488
HP
2257 }
2258 wl->pmk_list->pmkids.npmkid--;
1ce4784e 2259 } else
cf2b4488 2260 err = -EINVAL;
cf2b4488
HP
2261
2262 err = wl_update_pmklist(dev, wl->pmk_list, err);
2263
1ce4784e 2264 WL_TRACE("Exit\n");
cf2b4488
HP
2265 return err;
2266
2267}
2268
3e26416e 2269static s32
cf2b4488
HP
2270wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
2271{
2272 struct wl_priv *wl = wiphy_to_wl(wiphy);
3e26416e 2273 s32 err = 0;
cf2b4488 2274
1ce4784e 2275 WL_TRACE("Enter\n");
cf2b4488 2276 CHECK_SYS_UP();
1ce4784e 2277
cf2b4488
HP
2278 memset(wl->pmk_list, 0, sizeof(*wl->pmk_list));
2279 err = wl_update_pmklist(dev, wl->pmk_list, err);
1ce4784e
SS
2280
2281 WL_TRACE("Exit\n");
cf2b4488
HP
2282 return err;
2283
2284}
2285
2286static struct cfg80211_ops wl_cfg80211_ops = {
2287 .change_virtual_intf = wl_cfg80211_change_iface,
2288 .scan = wl_cfg80211_scan,
2289 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
2290 .join_ibss = wl_cfg80211_join_ibss,
2291 .leave_ibss = wl_cfg80211_leave_ibss,
2292 .get_station = wl_cfg80211_get_station,
2293 .set_tx_power = wl_cfg80211_set_tx_power,
2294 .get_tx_power = wl_cfg80211_get_tx_power,
2295 .add_key = wl_cfg80211_add_key,
2296 .del_key = wl_cfg80211_del_key,
2297 .get_key = wl_cfg80211_get_key,
2298 .set_default_key = wl_cfg80211_config_default_key,
2299 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
2300 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
2301 .set_bitrate_mask = wl_cfg80211_set_bitrate_mask,
2302 .connect = wl_cfg80211_connect,
2303 .disconnect = wl_cfg80211_disconnect,
2304 .suspend = wl_cfg80211_suspend,
2305 .resume = wl_cfg80211_resume,
2306 .set_pmksa = wl_cfg80211_set_pmksa,
2307 .del_pmksa = wl_cfg80211_del_pmksa,
2308 .flush_pmksa = wl_cfg80211_flush_pmksa
2309};
2310
3e26416e 2311static s32 wl_mode_to_nl80211_iftype(s32 mode)
cf2b4488 2312{
3e26416e 2313 s32 err = 0;
cf2b4488
HP
2314
2315 switch (mode) {
2316 case WL_MODE_BSS:
2317 return NL80211_IFTYPE_STATION;
2318 case WL_MODE_IBSS:
2319 return NL80211_IFTYPE_ADHOC;
2320 default:
2321 return NL80211_IFTYPE_UNSPECIFIED;
2322 }
2323
2324 return err;
2325}
2326
3e26416e 2327static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
cf2b4488
HP
2328 struct device *dev)
2329{
2330 struct wireless_dev *wdev;
3e26416e 2331 s32 err = 0;
cf2b4488
HP
2332
2333 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2334 if (unlikely(!wdev)) {
f4528696 2335 WL_ERR("Could not allocate wireless device\n");
cf2b4488
HP
2336 return ERR_PTR(-ENOMEM);
2337 }
2338 wdev->wiphy =
2339 wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface);
2340 if (unlikely(!wdev->wiphy)) {
f4528696 2341 WL_ERR("Couldn not allocate wiphy device\n");
cf2b4488
HP
2342 err = -ENOMEM;
2343 goto wiphy_new_out;
2344 }
2345 set_wiphy_dev(wdev->wiphy, dev);
2346 wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
2347 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
2348 wdev->wiphy->interface_modes =
2349 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
2350 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
2351 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
2352 * it as 11a by default.
2353 * This will be updated with
2354 * 11n phy tables in
2355 * "ifconfig up"
2356 * if phy has 11n capability
2357 */
2358 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
2359 wdev->wiphy->cipher_suites = __wl_cipher_suites;
2360 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
2361#ifndef WL_POWERSAVE_DISABLED
2362 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
2363 * save mode
2364 * by default
2365 */
2366#else
2367 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
2368#endif /* !WL_POWERSAVE_DISABLED */
76c06459
JC
2369 err = wiphy_register(wdev->wiphy);
2370 if (unlikely(err < 0)) {
f4528696 2371 WL_ERR("Couldn not register wiphy device (%d)\n", err);
cf2b4488
HP
2372 goto wiphy_register_out;
2373 }
2374 return wdev;
2375
2376wiphy_register_out:
2377 wiphy_free(wdev->wiphy);
2378
2379wiphy_new_out:
2380 kfree(wdev);
2381
2382 return ERR_PTR(err);
2383}
2384
2385static void wl_free_wdev(struct wl_priv *wl)
2386{
2387 struct wireless_dev *wdev = wl_to_wdev(wl);
2388
2389 if (unlikely(!wdev)) {
f4528696 2390 WL_ERR("wdev is invalid\n");
cf2b4488
HP
2391 return;
2392 }
2393 wiphy_unregister(wdev->wiphy);
2394 wiphy_free(wdev->wiphy);
2395 kfree(wdev);
2396 wl_to_wdev(wl) = NULL;
2397}
2398
3e26416e 2399static s32 wl_inform_bss(struct wl_priv *wl)
cf2b4488
HP
2400{
2401 struct wl_scan_results *bss_list;
2402 struct wl_bss_info *bi = NULL; /* must be initialized */
3e26416e 2403 s32 err = 0;
cf2b4488
HP
2404 int i;
2405
2406 bss_list = wl->bss_list;
2407 if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) {
f4528696
JP
2408 WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
2409 bss_list->version);
cf2b4488
HP
2410 return -EOPNOTSUPP;
2411 }
1ce4784e 2412 WL_SCAN("scanned AP count (%d)\n", bss_list->count);
cf2b4488
HP
2413 bi = next_bss(bss_list, bi);
2414 for_each_bss(bss_list, bi, i) {
76c06459
JC
2415 err = wl_inform_single_bss(wl, bi);
2416 if (unlikely(err))
cf2b4488
HP
2417 break;
2418 }
2419 return err;
2420}
2421
75494966 2422
3e26416e 2423static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
cf2b4488
HP
2424{
2425 struct wiphy *wiphy = wl_to_wiphy(wl);
75494966
SS
2426 struct ieee80211_channel *notify_channel;
2427 struct cfg80211_bss *bss;
cf2b4488 2428 struct ieee80211_supported_band *band;
3e26416e 2429 s32 err = 0;
75494966
SS
2430 u16 channel;
2431 u32 freq;
2432 u64 notify_timestamp;
2433 u16 notify_capability;
2434 u16 notify_interval;
2435 u8 *notify_ie;
2436 size_t notify_ielen;
2437 s32 notify_signal;
cf2b4488 2438
29750b90 2439 if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) {
75494966
SS
2440 WL_ERR("Bss info is larger than buffer. Discarding\n");
2441 return 0;
cf2b4488 2442 }
fb693a71 2443
75494966
SS
2444 channel = bi->ctl_ch ? bi->ctl_ch :
2445 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2446
2447 if (channel <= CH_MAX_2G_CHANNEL)
cf2b4488
HP
2448 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2449 else
2450 band = wiphy->bands[IEEE80211_BAND_5GHZ];
75494966
SS
2451
2452 freq = ieee80211_channel_to_frequency(channel, band->band);
2453 notify_channel = ieee80211_get_channel(wiphy, freq);
2454
2455 notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
2456 notify_capability = le16_to_cpu(bi->capability);
2457 notify_interval = le16_to_cpu(bi->beacon_period);
2458 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2459 notify_ielen = le16_to_cpu(bi->ie_length);
2460 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2461
1ce4784e 2462 WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
75494966
SS
2463 bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
2464 bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
1ce4784e
SS
2465 WL_CONN("Channel: %d(%d)\n", channel, freq);
2466 WL_CONN("Capability: %X\n", notify_capability);
2467 WL_CONN("Beacon interval: %d\n", notify_interval);
2468 WL_CONN("Signal: %d\n", notify_signal);
2469 WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
75494966
SS
2470
2471 bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
2472 notify_timestamp, notify_capability, notify_interval, notify_ie,
2473 notify_ielen, notify_signal, GFP_KERNEL);
2474
2475 if (unlikely(!bss)) {
f4528696 2476 WL_ERR("cfg80211_inform_bss_frame error\n");
cf2b4488
HP
2477 return -EINVAL;
2478 }
cf2b4488
HP
2479
2480 return err;
2481}
2482
69274f02
SS
2483static s32
2484wl_inform_ibss(struct wl_priv *wl, struct net_device *dev, const u8 *bssid)
2485{
2486 struct wiphy *wiphy = wl_to_wiphy(wl);
2487 struct ieee80211_channel *notify_channel;
2488 struct wl_bss_info *bi = NULL;
2489 struct ieee80211_supported_band *band;
2490 u8 *buf = NULL;
2491 s32 err = 0;
2492 u16 channel;
2493 u32 freq;
2494 u64 notify_timestamp;
2495 u16 notify_capability;
2496 u16 notify_interval;
2497 u8 *notify_ie;
2498 size_t notify_ielen;
2499 s32 notify_signal;
2500
1ce4784e
SS
2501 WL_TRACE("Enter\n");
2502
69274f02
SS
2503 buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2504 if (buf == NULL) {
2505 WL_ERR("kzalloc() failed\n");
2506 err = -ENOMEM;
2507 goto CleanUp;
2508 }
2509
2510 *(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2511
2512 err = wl_dev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
2513 if (unlikely(err)) {
2514 WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
2515 goto CleanUp;
2516 }
2517
2518 bi = (wl_bss_info_t *)(buf + 4);
2519
2520 channel = bi->ctl_ch ? bi->ctl_ch :
2521 CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
2522
2523 if (channel <= CH_MAX_2G_CHANNEL)
2524 band = wiphy->bands[IEEE80211_BAND_2GHZ];
2525 else
2526 band = wiphy->bands[IEEE80211_BAND_5GHZ];
2527
2528 freq = ieee80211_channel_to_frequency(channel, band->band);
2529 notify_channel = ieee80211_get_channel(wiphy, freq);
2530
2531 notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
2532 notify_capability = le16_to_cpu(bi->capability);
2533 notify_interval = le16_to_cpu(bi->beacon_period);
2534 notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
2535 notify_ielen = le16_to_cpu(bi->ie_length);
2536 notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
2537
1ce4784e
SS
2538 WL_CONN("channel: %d(%d)\n", channel, freq);
2539 WL_CONN("capability: %X\n", notify_capability);
2540 WL_CONN("beacon interval: %d\n", notify_interval);
2541 WL_CONN("signal: %d\n", notify_signal);
2542 WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
69274f02
SS
2543
2544 cfg80211_inform_bss(wiphy, notify_channel, bssid,
2545 notify_timestamp, notify_capability, notify_interval,
2546 notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
2547
2548CleanUp:
2549
2550 kfree(buf);
2551
1ce4784e
SS
2552 WL_TRACE("Exit\n");
2553
69274f02
SS
2554 return err;
2555}
2556
cf2b4488
HP
2557static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e)
2558{
628f10ba 2559 u32 event = be32_to_cpu(e->event_type);
e494632e 2560 u32 status = be32_to_cpu(e->status);
cf2b4488 2561
e494632e 2562 if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) {
1ce4784e 2563 WL_CONN("Processing set ssid\n");
e494632e
SS
2564 wl->link_up = true;
2565 return true;
cf2b4488
HP
2566 }
2567
0965ae88 2568 return false;
cf2b4488
HP
2569}
2570
2571static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e)
2572{
628f10ba
SF
2573 u32 event = be32_to_cpu(e->event_type);
2574 u16 flags = be16_to_cpu(e->flags);
cf2b4488 2575
e494632e 2576 if (event == WLC_E_LINK && (!(flags & WLC_EVENT_MSG_LINK))) {
1ce4784e 2577 WL_CONN("Processing link down\n");
0f0881b0 2578 return true;
cf2b4488 2579 }
0965ae88 2580 return false;
cf2b4488
HP
2581}
2582
b3164c71 2583static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
2584{
628f10ba
SF
2585 u32 event = be32_to_cpu(e->event_type);
2586 u32 status = be32_to_cpu(e->status);
e494632e 2587 u16 flags = be16_to_cpu(e->flags);
b3164c71 2588
e494632e 2589 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) {
1ce4784e 2590 WL_CONN("Processing Link %s & no network found\n",
e494632e
SS
2591 flags & WLC_EVENT_MSG_LINK ? "up" : "down");
2592 return true;
2593 }
2594
2595 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
1ce4784e 2596 WL_CONN("Processing connecting & no network found\n");
e494632e 2597 return true;
b3164c71 2598 }
2599
0965ae88 2600 return false;
b3164c71 2601}
2602
3e26416e 2603static s32
cf2b4488
HP
2604wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
2605 const wl_event_msg_t *e, void *data)
2606{
3e26416e 2607 s32 err = 0;
cf2b4488
HP
2608
2609 if (wl_is_linkup(wl, e)) {
1ce4784e 2610 WL_CONN("Linkup\n");
cf2b4488 2611 if (wl_is_ibssmode(wl)) {
e494632e
SS
2612 wl_update_prof(wl, NULL, (void *)e->addr,
2613 WL_PROF_BSSID);
69274f02 2614 wl_inform_ibss(wl, ndev, e->addr);
e494632e
SS
2615 cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
2616 clear_bit(WL_STATUS_CONNECTING, &wl->status);
2617 set_bit(WL_STATUS_CONNECTED, &wl->status);
2618 } else
0f0881b0 2619 wl_bss_connect_done(wl, ndev, e, data, true);
cf2b4488 2620 } else if (wl_is_linkdown(wl, e)) {
1ce4784e 2621 WL_CONN("Linkdown\n");
e494632e
SS
2622 if (wl_is_ibssmode(wl)) {
2623 if (test_and_clear_bit(WL_STATUS_CONNECTED,
2624 &wl->status))
2625 wl_link_down(wl);
2626 } else {
2627 if (test_and_clear_bit(WL_STATUS_CONNECTED,
2628 &wl->status)) {
2629 cfg80211_disconnected(ndev, 0, NULL, 0,
2630 GFP_KERNEL);
2631 wl_link_down(wl);
2632 }
2633 }
cf2b4488 2634 wl_init_prof(wl->profile);
b3164c71 2635 } else if (wl_is_nonetwork(wl, e)) {
e494632e
SS
2636 if (wl_is_ibssmode(wl))
2637 clear_bit(WL_STATUS_CONNECTING, &wl->status);
2638 else
2639 wl_bss_connect_done(wl, ndev, e, data, false);
cf2b4488
HP
2640 }
2641
2642 return err;
2643}
2644
3e26416e 2645static s32
cf2b4488
HP
2646wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
2647 const wl_event_msg_t *e, void *data)
2648{
3e26416e 2649 s32 err = 0;
e494632e
SS
2650 u32 event = be32_to_cpu(e->event_type);
2651 u32 status = be32_to_cpu(e->status);
cf2b4488 2652
e494632e
SS
2653 if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
2654 if (test_bit(WL_STATUS_CONNECTED, &wl->status))
2655 wl_bss_roaming_done(wl, ndev, e, data);
2656 else
2657 wl_bss_connect_done(wl, ndev, e, data, true);
2658 }
cf2b4488
HP
2659
2660 return err;
2661}
2662
3e26416e
GKH
2663static __used s32
2664wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
cf2b4488
HP
2665{
2666 struct wl_priv *wl = ndev_to_wl(dev);
66cbd3ab 2667 u32 buflen;
cf2b4488
HP
2668
2669 buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
d7ddd169 2670 BUG_ON(!buflen);
cf2b4488
HP
2671
2672 return wl_dev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen);
2673}
2674
3e26416e 2675static s32
562c8850 2676wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
3e26416e 2677 s32 buf_len)
cf2b4488
HP
2678{
2679 struct wl_priv *wl = ndev_to_wl(dev);
66cbd3ab 2680 u32 len;
3e26416e 2681 s32 err = 0;
cf2b4488
HP
2682
2683 len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
d7ddd169 2684 BUG_ON(!len);
76c06459
JC
2685 err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
2686 WL_IOCTL_LEN_MAX);
2687 if (unlikely(err)) {
f4528696 2688 WL_ERR("error (%d)\n", err);
cf2b4488
HP
2689 return err;
2690 }
2691 memcpy(buf, wl->ioctl_buf, buf_len);
2692
2693 return err;
2694}
2695
3e26416e 2696static s32 wl_get_assoc_ies(struct wl_priv *wl)
cf2b4488
HP
2697{
2698 struct net_device *ndev = wl_to_ndev(wl);
2699 struct wl_assoc_ielen *assoc_info;
2700 struct wl_connect_info *conn_info = wl_to_conn(wl);
66cbd3ab
GKH
2701 u32 req_len;
2702 u32 resp_len;
3e26416e 2703 s32 err = 0;
cf2b4488 2704
e494632e
SS
2705 wl_clear_assoc_ies(wl);
2706
76c06459
JC
2707 err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
2708 WL_ASSOC_INFO_MAX);
2709 if (unlikely(err)) {
f4528696 2710 WL_ERR("could not get assoc info (%d)\n", err);
cf2b4488
HP
2711 return err;
2712 }
2713 assoc_info = (struct wl_assoc_ielen *)wl->extra_buf;
2714 req_len = assoc_info->req_len;
2715 resp_len = assoc_info->resp_len;
2716 if (req_len) {
76c06459
JC
2717 err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
2718 WL_ASSOC_INFO_MAX);
2719 if (unlikely(err)) {
f4528696 2720 WL_ERR("could not get assoc req (%d)\n", err);
cf2b4488
HP
2721 return err;
2722 }
2723 conn_info->req_ie_len = req_len;
2724 conn_info->req_ie =
2725 kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL);
2726 } else {
2727 conn_info->req_ie_len = 0;
2728 conn_info->req_ie = NULL;
2729 }
2730 if (resp_len) {
76c06459
JC
2731 err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
2732 WL_ASSOC_INFO_MAX);
2733 if (unlikely(err)) {
f4528696 2734 WL_ERR("could not get assoc resp (%d)\n", err);
cf2b4488
HP
2735 return err;
2736 }
2737 conn_info->resp_ie_len = resp_len;
2738 conn_info->resp_ie =
2739 kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL);
2740 } else {
2741 conn_info->resp_ie_len = 0;
2742 conn_info->resp_ie = NULL;
2743 }
1ce4784e 2744 WL_CONN("req len (%d) resp len (%d)\n",
f4528696 2745 conn_info->req_ie_len, conn_info->resp_ie_len);
cf2b4488
HP
2746
2747 return err;
2748}
2749
e494632e
SS
2750static void wl_clear_assoc_ies(struct wl_priv *wl)
2751{
2752 struct wl_connect_info *conn_info = wl_to_conn(wl);
2753
2754 kfree(conn_info->req_ie);
2755 conn_info->req_ie = NULL;
2756 conn_info->req_ie_len = 0;
2757 kfree(conn_info->resp_ie);
2758 conn_info->resp_ie = NULL;
2759 conn_info->resp_ie_len = 0;
2760}
2761
2762
fb693a71 2763static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
2764 size_t *join_params_size)
2765{
2766 chanspec_t chanspec = 0;
2767
2768 if (ch != 0) {
2769 join_params->params.chanspec_num = 1;
2770 join_params->params.chanspec_list[0] = ch;
2771
e494632e 2772 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
fb693a71 2773 chanspec |= WL_CHANSPEC_BAND_2G;
2774 else
2775 chanspec |= WL_CHANSPEC_BAND_5G;
2776
2777 chanspec |= WL_CHANSPEC_BW_20;
2778 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
2779
2780 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
2781 join_params->params.chanspec_num * sizeof(chanspec_t);
2782
2783 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
2784 join_params->params.chanspec_list[0] |= chanspec;
2785 join_params->params.chanspec_list[0] =
29750b90 2786 cpu_to_le16(join_params->params.chanspec_list[0]);
fb693a71 2787
2788 join_params->params.chanspec_num =
29750b90 2789 cpu_to_le32(join_params->params.chanspec_num);
fb693a71 2790
1ce4784e
SS
2791 WL_CONN("join_params->params.chanspec_list[0]= %#X,"
2792 "channel %d, chanspec %#X\n",
f4528696 2793 join_params->params.chanspec_list[0], ch, chanspec);
fb693a71 2794 }
2795}
2796
3e26416e 2797static s32 wl_update_bss_info(struct wl_priv *wl)
cf2b4488 2798{
cf2b4488
HP
2799 struct wl_bss_info *bi;
2800 struct wlc_ssid *ssid;
1e0645c3 2801 struct bcm_tlv *tim;
2802 u16 beacon_interval;
2803 u8 dtim_period;
2804 size_t ie_len;
2805 u8 *ie;
3e26416e 2806 s32 err = 0;
cf2b4488 2807
1ce4784e 2808 WL_TRACE("Enter\n");
cf2b4488
HP
2809 if (wl_is_ibssmode(wl))
2810 return err;
2811
2812 ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
cf2b4488 2813
e494632e
SS
2814 *(u32 *)wl->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
2815 err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO,
2816 wl->extra_buf, WL_EXTRA_BUF_MAX);
2817 if (unlikely(err)) {
2818 WL_ERR("Could not get bss info %d\n", err);
2819 goto update_bss_info_out;
cf2b4488
HP
2820 }
2821
e494632e
SS
2822 bi = (struct wl_bss_info *)(wl->extra_buf + 4);
2823 err = wl_inform_single_bss(wl, bi);
2824 if (unlikely(err))
2825 goto update_bss_info_out;
2826
2827 ie = ((u8 *)bi) + bi->ie_offset;
2828 ie_len = bi->ie_length;
2829 beacon_interval = cpu_to_le16(bi->beacon_period);
2830
1e0645c3 2831 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
e494632e 2832 if (tim)
1e0645c3 2833 dtim_period = tim->data[1];
e494632e 2834 else {
1e0645c3 2835 /*
2836 * active scan was done so we could not get dtim
2837 * information out of probe response.
2838 * so we speficially query dtim information to dongle.
2839 */
e494632e
SS
2840 u32 var;
2841 err = wl_dev_intvar_get(wl_to_ndev(wl), "dtim_assoc", &var);
1e0645c3 2842 if (unlikely(err)) {
e494632e 2843 WL_ERR("wl dtim_assoc failed (%d)\n", err);
1e0645c3 2844 goto update_bss_info_out;
2845 }
e494632e 2846 dtim_period = (u8)var;
1e0645c3 2847 }
2848
2849 wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
2850 wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
2851
cf2b4488 2852update_bss_info_out:
1ce4784e 2853 WL_TRACE("Exit");
cf2b4488
HP
2854 return err;
2855}
2856
3e26416e 2857static s32
cf2b4488
HP
2858wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
2859 const wl_event_msg_t *e, void *data)
2860{
2861 struct wl_connect_info *conn_info = wl_to_conn(wl);
3e26416e 2862 s32 err = 0;
cf2b4488 2863
1ce4784e
SS
2864 WL_TRACE("Enter\n");
2865
cf2b4488 2866 wl_get_assoc_ies(wl);
e494632e 2867 wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
cf2b4488 2868 wl_update_bss_info(wl);
e494632e 2869
ed9d0102 2870 cfg80211_roamed(ndev, NULL,
e494632e 2871 (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
cf2b4488
HP
2872 conn_info->req_ie, conn_info->req_ie_len,
2873 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
1ce4784e 2874 WL_CONN("Report roaming result\n");
cf2b4488
HP
2875
2876 set_bit(WL_STATUS_CONNECTED, &wl->status);
1ce4784e 2877 WL_TRACE("Exit\n");
cf2b4488
HP
2878 return err;
2879}
2880
3e26416e 2881static s32
cf2b4488 2882wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
b3164c71 2883 const wl_event_msg_t *e, void *data, bool completed)
cf2b4488
HP
2884{
2885 struct wl_connect_info *conn_info = wl_to_conn(wl);
3e26416e 2886 s32 err = 0;
cf2b4488 2887
1ce4784e 2888 WL_TRACE("Enter\n");
e494632e 2889
cf2b4488 2890 if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) {
e494632e
SS
2891 if (completed) {
2892 wl_get_assoc_ies(wl);
2893 wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
2894 wl_update_bss_info(wl);
2895 }
cf2b4488 2896 cfg80211_connect_result(ndev,
e494632e 2897 (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
cf2b4488
HP
2898 conn_info->req_ie,
2899 conn_info->req_ie_len,
2900 conn_info->resp_ie,
2901 conn_info->resp_ie_len,
b3164c71 2902 completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
2903 GFP_KERNEL);
e494632e
SS
2904 if (completed)
2905 set_bit(WL_STATUS_CONNECTED, &wl->status);
1ce4784e 2906 WL_CONN("Report connect result - connection %s\n",
e494632e 2907 completed ? "succeeded" : "failed");
cf2b4488 2908 }
1ce4784e 2909 WL_TRACE("Exit\n");
cf2b4488
HP
2910 return err;
2911}
2912
3e26416e 2913static s32
cf2b4488
HP
2914wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
2915 const wl_event_msg_t *e, void *data)
2916{
628f10ba 2917 u16 flags = be16_to_cpu(e->flags);
cf2b4488
HP
2918 enum nl80211_key_type key_type;
2919
2920 rtnl_lock();
2921 if (flags & WLC_EVENT_MSG_GROUP)
2922 key_type = NL80211_KEYTYPE_GROUP;
2923 else
2924 key_type = NL80211_KEYTYPE_PAIRWISE;
2925
3fd79f7c 2926 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
cf2b4488
HP
2927 NULL, GFP_KERNEL);
2928 rtnl_unlock();
2929
2930 return 0;
2931}
2932
3e26416e 2933static s32
cf2b4488
HP
2934wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
2935 const wl_event_msg_t *e, void *data)
2936{
2937 struct channel_info channel_inform;
2938 struct wl_scan_results *bss_list;
66cbd3ab 2939 u32 len = WL_SCAN_BUF_MAX;
3e26416e 2940 s32 err = 0;
9446af06 2941 bool scan_abort = false;
cf2b4488 2942
1ce4784e
SS
2943 WL_TRACE("Enter\n");
2944
2945 if (wl->iscan_on && wl->iscan_kickstart) {
2946 WL_TRACE("Exit\n");
cf2b4488 2947 return wl_wakeup_iscan(wl_to_iscan(wl));
1ce4784e 2948 }
cf2b4488
HP
2949
2950 if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
f4528696 2951 WL_ERR("Scan complete while device not scanning\n");
9446af06
SS
2952 scan_abort = true;
2953 err = -EINVAL;
2954 goto scan_done_out;
cf2b4488 2955 }
9446af06 2956
76c06459
JC
2957 err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
2958 sizeof(channel_inform));
2959 if (unlikely(err)) {
f4528696 2960 WL_ERR("scan busy (%d)\n", err);
9446af06 2961 scan_abort = true;
cf2b4488
HP
2962 goto scan_done_out;
2963 }
29750b90 2964 channel_inform.scan_channel = le32_to_cpu(channel_inform.scan_channel);
cf2b4488
HP
2965 if (unlikely(channel_inform.scan_channel)) {
2966
1ce4784e 2967 WL_CONN("channel_inform.scan_channel (%d)\n",
f4528696 2968 channel_inform.scan_channel);
cf2b4488
HP
2969 }
2970 wl->bss_list = wl->scan_results;
2971 bss_list = wl->bss_list;
2972 memset(bss_list, 0, len);
29750b90 2973 bss_list->buflen = cpu_to_le32(len);
9446af06 2974
76c06459
JC
2975 err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len);
2976 if (unlikely(err)) {
f4528696 2977 WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
cf2b4488 2978 err = -EINVAL;
9446af06 2979 scan_abort = true;
cf2b4488
HP
2980 goto scan_done_out;
2981 }
29750b90
SF
2982 bss_list->buflen = le32_to_cpu(bss_list->buflen);
2983 bss_list->version = le32_to_cpu(bss_list->version);
2984 bss_list->count = le32_to_cpu(bss_list->count);
cf2b4488 2985
76c06459 2986 err = wl_inform_bss(wl);
9446af06
SS
2987 if (err) {
2988 scan_abort = true;
cf2b4488 2989 goto scan_done_out;
9446af06 2990 }
cf2b4488
HP
2991
2992scan_done_out:
2993 if (wl->scan_request) {
1ce4784e 2994 WL_SCAN("calling cfg80211_scan_done\n");
9446af06 2995 cfg80211_scan_done(wl->scan_request, scan_abort);
fb693a71 2996 wl_set_mpc(ndev, 1);
cf2b4488
HP
2997 wl->scan_request = NULL;
2998 }
1ce4784e
SS
2999
3000 WL_TRACE("Exit\n");
3001
cf2b4488
HP
3002 return err;
3003}
3004
3005static void wl_init_conf(struct wl_conf *conf)
3006{
66cbd3ab
GKH
3007 conf->mode = (u32)-1;
3008 conf->frag_threshold = (u32)-1;
3009 conf->rts_threshold = (u32)-1;
3010 conf->retry_short = (u32)-1;
3011 conf->retry_long = (u32)-1;
e9887c9d 3012 conf->tx_power = -1;
cf2b4488
HP
3013}
3014
3015static void wl_init_prof(struct wl_profile *prof)
3016{
3017 memset(prof, 0, sizeof(*prof));
3018}
3019
3020static void wl_init_eloop_handler(struct wl_event_loop *el)
3021{
3022 memset(el, 0, sizeof(*el));
3023 el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
cf2b4488 3024 el->handler[WLC_E_LINK] = wl_notify_connect_status;
cf2b4488
HP
3025 el->handler[WLC_E_ROAM] = wl_notify_roaming_status;
3026 el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
b3164c71 3027 el->handler[WLC_E_SET_SSID] = wl_notify_connect_status;
cf2b4488
HP
3028}
3029
3e26416e 3030static s32 wl_init_priv_mem(struct wl_priv *wl)
cf2b4488 3031{
3b785a8c 3032 wl->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
cf2b4488 3033 if (unlikely(!wl->scan_results)) {
f4528696 3034 WL_ERR("Scan results alloc failed\n");
cf2b4488
HP
3035 goto init_priv_mem_out;
3036 }
3b785a8c 3037 wl->conf = kzalloc(sizeof(*wl->conf), GFP_KERNEL);
cf2b4488 3038 if (unlikely(!wl->conf)) {
f4528696 3039 WL_ERR("wl_conf alloc failed\n");
cf2b4488
HP
3040 goto init_priv_mem_out;
3041 }
3b785a8c 3042 wl->profile = kzalloc(sizeof(*wl->profile), GFP_KERNEL);
cf2b4488 3043 if (unlikely(!wl->profile)) {
f4528696 3044 WL_ERR("wl_profile alloc failed\n");
cf2b4488
HP
3045 goto init_priv_mem_out;
3046 }
3b785a8c 3047 wl->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
cf2b4488 3048 if (unlikely(!wl->bss_info)) {
f4528696 3049 WL_ERR("Bss information alloc failed\n");
cf2b4488
HP
3050 goto init_priv_mem_out;
3051 }
3b785a8c 3052 wl->scan_req_int = kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
cf2b4488 3053 if (unlikely(!wl->scan_req_int)) {
f4528696 3054 WL_ERR("Scan req alloc failed\n");
cf2b4488
HP
3055 goto init_priv_mem_out;
3056 }
3b785a8c 3057 wl->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
cf2b4488 3058 if (unlikely(!wl->ioctl_buf)) {
f4528696 3059 WL_ERR("Ioctl buf alloc failed\n");
cf2b4488
HP
3060 goto init_priv_mem_out;
3061 }
3b785a8c 3062 wl->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
cf2b4488 3063 if (unlikely(!wl->extra_buf)) {
f4528696 3064 WL_ERR("Extra buf alloc failed\n");
cf2b4488
HP
3065 goto init_priv_mem_out;
3066 }
3b785a8c 3067 wl->iscan = kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
cf2b4488 3068 if (unlikely(!wl->iscan)) {
f4528696 3069 WL_ERR("Iscan buf alloc failed\n");
cf2b4488
HP
3070 goto init_priv_mem_out;
3071 }
3b785a8c 3072 wl->fw = kzalloc(sizeof(*wl->fw), GFP_KERNEL);
cf2b4488 3073 if (unlikely(!wl->fw)) {
f4528696 3074 WL_ERR("fw object alloc failed\n");
cf2b4488
HP
3075 goto init_priv_mem_out;
3076 }
3b785a8c 3077 wl->pmk_list = kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
cf2b4488 3078 if (unlikely(!wl->pmk_list)) {
f4528696 3079 WL_ERR("pmk list alloc failed\n");
cf2b4488
HP
3080 goto init_priv_mem_out;
3081 }
3082
3083 return 0;
3084
3085init_priv_mem_out:
3086 wl_deinit_priv_mem(wl);
3087
3088 return -ENOMEM;
3089}
3090
3091static void wl_deinit_priv_mem(struct wl_priv *wl)
3092{
3093 kfree(wl->scan_results);
3094 wl->scan_results = NULL;
3095 kfree(wl->bss_info);
3096 wl->bss_info = NULL;
3097 kfree(wl->conf);
3098 wl->conf = NULL;
3099 kfree(wl->profile);
3100 wl->profile = NULL;
3101 kfree(wl->scan_req_int);
3102 wl->scan_req_int = NULL;
3103 kfree(wl->ioctl_buf);
3104 wl->ioctl_buf = NULL;
3105 kfree(wl->extra_buf);
3106 wl->extra_buf = NULL;
3107 kfree(wl->iscan);
3108 wl->iscan = NULL;
3109 kfree(wl->fw);
3110 wl->fw = NULL;
3111 kfree(wl->pmk_list);
3112 wl->pmk_list = NULL;
3113}
3114
3e26416e 3115static s32 wl_create_event_handler(struct wl_priv *wl)
cf2b4488
HP
3116{
3117 sema_init(&wl->event_sync, 0);
7716314b
JC
3118 wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler");
3119 if (IS_ERR(wl->event_tsk)) {
3120 wl->event_tsk = NULL;
f4528696 3121 WL_ERR("failed to create event thread\n");
cf2b4488
HP
3122 return -ENOMEM;
3123 }
cf2b4488
HP
3124 return 0;
3125}
3126
3127static void wl_destroy_event_handler(struct wl_priv *wl)
3128{
7716314b 3129 if (wl->event_tsk) {
7356f429 3130 send_sig(SIGTERM, wl->event_tsk, 1);
7716314b
JC
3131 kthread_stop(wl->event_tsk);
3132 wl->event_tsk = NULL;
cf2b4488
HP
3133 }
3134}
3135
3136static void wl_term_iscan(struct wl_priv *wl)
3137{
3138 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
3139
7716314b 3140 if (wl->iscan_on && iscan->tsk) {
cf2b4488 3141 iscan->state = WL_ISCAN_STATE_IDLE;
7356f429 3142 send_sig(SIGTERM, iscan->tsk, 1);
7716314b
JC
3143 kthread_stop(iscan->tsk);
3144 iscan->tsk = NULL;
cf2b4488
HP
3145 }
3146}
3147
3148static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
3149{
3150 struct wl_priv *wl = iscan_to_wl(iscan);
fb693a71 3151 struct net_device *ndev = wl_to_ndev(wl);
cf2b4488
HP
3152
3153 if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
f4528696 3154 WL_ERR("Scan complete while device not scanning\n");
cf2b4488
HP
3155 return;
3156 }
3157 if (likely(wl->scan_request)) {
1ce4784e
SS
3158 WL_SCAN("ISCAN Completed scan: %s\n",
3159 aborted ? "Aborted" : "Done");
cf2b4488 3160 cfg80211_scan_done(wl->scan_request, aborted);
fb693a71 3161 wl_set_mpc(ndev, 1);
cf2b4488
HP
3162 wl->scan_request = NULL;
3163 }
0965ae88 3164 wl->iscan_kickstart = false;
cf2b4488
HP
3165}
3166
3e26416e 3167static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan)
cf2b4488
HP
3168{
3169 if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) {
1ce4784e 3170 WL_SCAN("wake up iscan\n");
cf2b4488
HP
3171 up(&iscan->sync);
3172 return 0;
3173 }
3174
3175 return -EIO;
3176}
3177
3e26416e 3178static s32
66cbd3ab 3179wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
cf2b4488
HP
3180 struct wl_scan_results **bss_list)
3181{
3182 struct wl_iscan_results list;
3183 struct wl_scan_results *results;
3184 struct wl_iscan_results *list_buf;
3e26416e 3185 s32 err = 0;
cf2b4488
HP
3186
3187 memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
3188 list_buf = (struct wl_iscan_results *)iscan->scan_buf;
3189 results = &list_buf->results;
3190 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
3191 results->version = 0;
3192 results->count = 0;
3193
3194 memset(&list, 0, sizeof(list));
29750b90 3195 list.results.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
76c06459
JC
3196 err = wl_dev_iovar_getbuf(iscan->dev, "iscanresults", &list,
3197 WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
3198 WL_ISCAN_BUF_MAX);
3199 if (unlikely(err)) {
f4528696 3200 WL_ERR("error (%d)\n", err);
cf2b4488
HP
3201 return err;
3202 }
29750b90
SF
3203 results->buflen = le32_to_cpu(results->buflen);
3204 results->version = le32_to_cpu(results->version);
3205 results->count = le32_to_cpu(results->count);
1ce4784e
SS
3206 WL_SCAN("results->count = %d\n", results->count);
3207 WL_SCAN("results->buflen = %d\n", results->buflen);
29750b90 3208 *status = le32_to_cpu(list_buf->status);
cf2b4488
HP
3209 *bss_list = results;
3210
3211 return err;
3212}
3213
3e26416e 3214static s32 wl_iscan_done(struct wl_priv *wl)
cf2b4488
HP
3215{
3216 struct wl_iscan_ctrl *iscan = wl->iscan;
3e26416e 3217 s32 err = 0;
cf2b4488
HP
3218
3219 iscan->state = WL_ISCAN_STATE_IDLE;
3220 rtnl_lock();
3221 wl_inform_bss(wl);
0965ae88 3222 wl_notify_iscan_complete(iscan, false);
cf2b4488
HP
3223 rtnl_unlock();
3224
3225 return err;
3226}
3227
3e26416e 3228static s32 wl_iscan_pending(struct wl_priv *wl)
cf2b4488
HP
3229{
3230 struct wl_iscan_ctrl *iscan = wl->iscan;
3e26416e 3231 s32 err = 0;
cf2b4488
HP
3232
3233 /* Reschedule the timer */
3234 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
3235 iscan->timer_on = 1;
3236
3237 return err;
3238}
3239
3e26416e 3240static s32 wl_iscan_inprogress(struct wl_priv *wl)
cf2b4488
HP
3241{
3242 struct wl_iscan_ctrl *iscan = wl->iscan;
3e26416e 3243 s32 err = 0;
cf2b4488
HP
3244
3245 rtnl_lock();
3246 wl_inform_bss(wl);
3247 wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
3248 rtnl_unlock();
3249 /* Reschedule the timer */
3250 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
3251 iscan->timer_on = 1;
3252
3253 return err;
3254}
3255
3e26416e 3256static s32 wl_iscan_aborted(struct wl_priv *wl)
cf2b4488
HP
3257{
3258 struct wl_iscan_ctrl *iscan = wl->iscan;
3e26416e 3259 s32 err = 0;
cf2b4488
HP
3260
3261 iscan->state = WL_ISCAN_STATE_IDLE;
3262 rtnl_lock();
0f0881b0 3263 wl_notify_iscan_complete(iscan, true);
cf2b4488
HP
3264 rtnl_unlock();
3265
3266 return err;
3267}
3268
3e26416e 3269static s32 wl_iscan_thread(void *data)
cf2b4488
HP
3270{
3271 struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
3272 struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
3273 struct wl_priv *wl = iscan_to_wl(iscan);
3274 struct wl_iscan_eloop *el = &iscan->el;
66cbd3ab 3275 u32 status;
cf2b4488
HP
3276 int err = 0;
3277
3278 sched_setscheduler(current, SCHED_FIFO, &param);
af737136 3279 allow_signal(SIGTERM);
cf2b4488
HP
3280 status = WL_SCAN_RESULTS_PARTIAL;
3281 while (likely(!down_interruptible(&iscan->sync))) {
7716314b
JC
3282 if (kthread_should_stop())
3283 break;
cf2b4488
HP
3284 if (iscan->timer_on) {
3285 del_timer_sync(&iscan->timer);
3286 iscan->timer_on = 0;
3287 }
3288 rtnl_lock();
76c06459
JC
3289 err = wl_get_iscan_results(iscan, &status, &wl->bss_list);
3290 if (unlikely(err)) {
cf2b4488 3291 status = WL_SCAN_RESULTS_ABORTED;
f4528696 3292 WL_ERR("Abort iscan\n");
cf2b4488
HP
3293 }
3294 rtnl_unlock();
3295 el->handler[status] (wl);
3296 }
3297 if (iscan->timer_on) {
3298 del_timer_sync(&iscan->timer);
3299 iscan->timer_on = 0;
3300 }
1ce4784e 3301 WL_SCAN("ISCAN thread terminated\n");
cf2b4488
HP
3302
3303 return 0;
3304}
3305
3deea904 3306static void wl_iscan_timer(unsigned long data)
cf2b4488
HP
3307{
3308 struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
3309
3310 if (iscan) {
3311 iscan->timer_on = 0;
1ce4784e 3312 WL_SCAN("timer expired\n");
cf2b4488
HP
3313 wl_wakeup_iscan(iscan);
3314 }
3315}
3316
3e26416e 3317static s32 wl_invoke_iscan(struct wl_priv *wl)
cf2b4488
HP
3318{
3319 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
3320 int err = 0;
3321
7716314b 3322 if (wl->iscan_on && !iscan->tsk) {
cf2b4488
HP
3323 iscan->state = WL_ISCAN_STATE_IDLE;
3324 sema_init(&iscan->sync, 0);
7716314b
JC
3325 iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
3326 if (IS_ERR(iscan->tsk)) {
f4528696 3327 WL_ERR("Could not create iscan thread\n");
7716314b 3328 iscan->tsk = NULL;
cf2b4488
HP
3329 return -ENOMEM;
3330 }
3331 }
3332
3333 return err;
3334}
3335
3336static void wl_init_iscan_eloop(struct wl_iscan_eloop *el)
3337{
3338 memset(el, 0, sizeof(*el));
3339 el->handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done;
3340 el->handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress;
3341 el->handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending;
3342 el->handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted;
3343 el->handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
3344}
3345
3e26416e 3346static s32 wl_init_iscan(struct wl_priv *wl)
cf2b4488
HP
3347{
3348 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
3349 int err = 0;
3350
3351 if (wl->iscan_on) {
3352 iscan->dev = wl_to_ndev(wl);
3353 iscan->state = WL_ISCAN_STATE_IDLE;
3354 wl_init_iscan_eloop(&iscan->el);
3355 iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
3356 init_timer(&iscan->timer);
3deea904 3357 iscan->timer.data = (unsigned long) iscan;
cf2b4488
HP
3358 iscan->timer.function = wl_iscan_timer;
3359 sema_init(&iscan->sync, 0);
7716314b
JC
3360 iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
3361 if (IS_ERR(iscan->tsk)) {
f4528696 3362 WL_ERR("Could not create iscan thread\n");
7716314b 3363 iscan->tsk = NULL;
cf2b4488
HP
3364 return -ENOMEM;
3365 }
3366 iscan->data = wl;
3367 }
3368
3369 return err;
3370}
3371
3372static void wl_init_fw(struct wl_fw_ctrl *fw)
3373{
3374 fw->status = 0; /* init fw loading status.
3375 0 means nothing was loaded yet */
3376}
3377
3e26416e 3378static s32 wl_init_priv(struct wl_priv *wl)
cf2b4488
HP
3379{
3380 struct wiphy *wiphy = wl_to_wiphy(wl);
3e26416e 3381 s32 err = 0;
cf2b4488
HP
3382
3383 wl->scan_request = NULL;
3384 wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
0f0881b0 3385 wl->iscan_on = true; /* iscan on & off switch.
cf2b4488 3386 we enable iscan per default */
f49200c3 3387 wl->roam_on = false; /* roam on & off switch.
cf2b4488 3388 we enable roam per default */
cf2b4488 3389
0965ae88 3390 wl->iscan_kickstart = false;
0f0881b0 3391 wl->active_scan = true; /* we do active scan for
cf2b4488 3392 specific scan per default */
0965ae88 3393 wl->dongle_up = false; /* dongle is not up yet */
cf2b4488 3394 wl_init_eq(wl);
76c06459
JC
3395 err = wl_init_priv_mem(wl);
3396 if (unlikely(err))
cf2b4488
HP
3397 return err;
3398 if (unlikely(wl_create_event_handler(wl)))
3399 return -ENOMEM;
3400 wl_init_eloop_handler(&wl->el);
3401 mutex_init(&wl->usr_sync);
76c06459
JC
3402 err = wl_init_iscan(wl);
3403 if (unlikely(err))
cf2b4488
HP
3404 return err;
3405 wl_init_fw(wl->fw);
3406 wl_init_conf(wl->conf);
3407 wl_init_prof(wl->profile);
3408 wl_link_down(wl);
3409
3410 return err;
3411}
3412
3413static void wl_deinit_priv(struct wl_priv *wl)
3414{
3415 wl_destroy_event_handler(wl);
0965ae88 3416 wl->dongle_up = false; /* dongle down */
cf2b4488
HP
3417 wl_flush_eq(wl);
3418 wl_link_down(wl);
3419 wl_term_iscan(wl);
3420 wl_deinit_priv_mem(wl);
3421}
3422
3e26416e 3423s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
cf2b4488
HP
3424{
3425 struct wireless_dev *wdev;
3426 struct wl_priv *wl;
3427 struct wl_iface *ci;
3e26416e 3428 s32 err = 0;
cf2b4488
HP
3429
3430 if (unlikely(!ndev)) {
f4528696 3431 WL_ERR("ndev is invalid\n");
cf2b4488
HP
3432 return -ENODEV;
3433 }
3434 wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL);
3435 if (unlikely(!wl_cfg80211_dev)) {
f4528696 3436 WL_ERR("wl_cfg80211_dev is invalid\n");
cf2b4488
HP
3437 return -ENOMEM;
3438 }
1ce4784e 3439 WL_INFO("func %p\n", wl_cfg80211_get_sdio_func());
93ad12cf 3440 wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev);
310d6052 3441 if (IS_ERR(wdev))
cf2b4488
HP
3442 return -ENOMEM;
3443
3444 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
3445 wl = wdev_to_wl(wdev);
3446 wl->wdev = wdev;
3447 wl->pub = data;
3448 ci = (struct wl_iface *)wl_to_ci(wl);
3449 ci->wl = wl;
3450 ndev->ieee80211_ptr = wdev;
fb693a71 3451 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
cf2b4488 3452 wdev->netdev = ndev;
76c06459
JC
3453 err = wl_init_priv(wl);
3454 if (unlikely(err)) {
f4528696 3455 WL_ERR("Failed to init iwm_priv (%d)\n", err);
cf2b4488
HP
3456 goto cfg80211_attach_out;
3457 }
3458 wl_set_drvdata(wl_cfg80211_dev, ci);
cf2b4488
HP
3459
3460 return err;
3461
3462cfg80211_attach_out:
3463 wl_free_wdev(wl);
3464 return err;
3465}
3466
3467void wl_cfg80211_detach(void)
3468{
3469 struct wl_priv *wl;
3470
3471 wl = WL_PRIV_GET();
3472
3473 wl_deinit_priv(wl);
3474 wl_free_wdev(wl);
3475 wl_set_drvdata(wl_cfg80211_dev, NULL);
3476 kfree(wl_cfg80211_dev);
3477 wl_cfg80211_dev = NULL;
3478 wl_clear_sdio_func();
3479}
3480
3481static void wl_wakeup_event(struct wl_priv *wl)
3482{
3483 up(&wl->event_sync);
3484}
3485
3e26416e 3486static s32 wl_event_handler(void *data)
cf2b4488
HP
3487{
3488 struct wl_priv *wl = (struct wl_priv *)data;
3489 struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
3490 struct wl_event_q *e;
3491
3492 sched_setscheduler(current, SCHED_FIFO, &param);
af737136 3493 allow_signal(SIGTERM);
cf2b4488 3494 while (likely(!down_interruptible(&wl->event_sync))) {
eeb8e46b 3495 if (kthread_should_stop())
7716314b 3496 break;
76c06459
JC
3497 e = wl_deq_event(wl);
3498 if (unlikely(!e)) {
f4528696 3499 WL_ERR("event queue empty...\n");
cf2b4488
HP
3500 BUG();
3501 }
1ce4784e 3502 WL_INFO("event type (%d)\n", e->etype);
cf2b4488
HP
3503 if (wl->el.handler[e->etype]) {
3504 wl->el.handler[e->etype] (wl, wl_to_ndev(wl), &e->emsg,
3505 e->edata);
3506 } else {
1ce4784e 3507 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
cf2b4488
HP
3508 }
3509 wl_put_event(e);
3510 }
1ce4784e 3511 WL_INFO("was terminated\n");
7716314b 3512 return 0;
cf2b4488
HP
3513}
3514
3515void
3516wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
3517{
628f10ba 3518 u32 event_type = be32_to_cpu(e->event_type);
cf2b4488 3519 struct wl_priv *wl = ndev_to_wl(ndev);
1ce4784e 3520
cf2b4488
HP
3521 if (likely(!wl_enq_event(wl, event_type, e, data)))
3522 wl_wakeup_event(wl);
3523}
3524
3525static void wl_init_eq(struct wl_priv *wl)
3526{
3527 wl_init_eq_lock(wl);
3528 INIT_LIST_HEAD(&wl->eq_list);
3529}
3530
3531static void wl_flush_eq(struct wl_priv *wl)
3532{
3533 struct wl_event_q *e;
3534
3535 wl_lock_eq(wl);
3536 while (!list_empty(&wl->eq_list)) {
3537 e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
3538 list_del(&e->eq_list);
3539 kfree(e);
3540 }
3541 wl_unlock_eq(wl);
3542}
3543
3544/*
3545* retrieve first queued event from head
3546*/
3547
3548static struct wl_event_q *wl_deq_event(struct wl_priv *wl)
3549{
3550 struct wl_event_q *e = NULL;
3551
3552 wl_lock_eq(wl);
3553 if (likely(!list_empty(&wl->eq_list))) {
3554 e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
3555 list_del(&e->eq_list);
3556 }
3557 wl_unlock_eq(wl);
3558
3559 return e;
3560}
3561
3562/*
3563** push event to tail of the queue
3564*/
3565
3e26416e 3566static s32
66cbd3ab 3567wl_enq_event(struct wl_priv *wl, u32 event, const wl_event_msg_t *msg,
cf2b4488
HP
3568 void *data)
3569{
3570 struct wl_event_q *e;
3e26416e 3571 s32 err = 0;
cf2b4488 3572
76c06459
JC
3573 e = kzalloc(sizeof(struct wl_event_q), GFP_KERNEL);
3574 if (unlikely(!e)) {
f4528696 3575 WL_ERR("event alloc failed\n");
cf2b4488
HP
3576 return -ENOMEM;
3577 }
3578
3579 e->etype = event;
3580 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
3581 if (data) {
3582 }
3583 wl_lock_eq(wl);
3584 list_add_tail(&e->eq_list, &wl->eq_list);
3585 wl_unlock_eq(wl);
3586
3587 return err;
3588}
3589
3590static void wl_put_event(struct wl_event_q *e)
3591{
3592 kfree(e);
3593}
3594
3595void wl_cfg80211_sdio_func(void *func)
3596{
3597 cfg80211_sdio_func = (struct sdio_func *)func;
3598}
3599
3600static void wl_clear_sdio_func(void)
3601{
3602 cfg80211_sdio_func = NULL;
3603}
3604
93ad12cf 3605struct sdio_func *wl_cfg80211_get_sdio_func(void)
cf2b4488
HP
3606{
3607 return cfg80211_sdio_func;
3608}
3609
3e26416e 3610static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
cf2b4488 3611{
3e26416e 3612 s32 infra = 0;
3e26416e 3613 s32 err = 0;
cf2b4488
HP
3614
3615 switch (iftype) {
3616 case NL80211_IFTYPE_MONITOR:
3617 case NL80211_IFTYPE_WDS:
f4528696
JP
3618 WL_ERR("type (%d) : currently we do not support this mode\n",
3619 iftype);
cf2b4488
HP
3620 err = -EINVAL;
3621 return err;
3622 case NL80211_IFTYPE_ADHOC:
69274f02 3623 infra = 0;
cf2b4488
HP
3624 break;
3625 case NL80211_IFTYPE_STATION:
3626 infra = 1;
3627 break;
3628 default:
3629 err = -EINVAL;
f4528696 3630 WL_ERR("invalid type (%d)\n", iftype);
cf2b4488
HP
3631 return err;
3632 }
29750b90 3633 infra = cpu_to_le32(infra);
76c06459
JC
3634 err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
3635 if (unlikely(err)) {
f4528696 3636 WL_ERR("WLC_SET_INFRA error (%d)\n", err);
cf2b4488
HP
3637 return err;
3638 }
3639
69274f02 3640 return 0;
cf2b4488
HP
3641}
3642
3643#ifndef EMBEDDED_PLATFORM
3e26416e 3644static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
cf2b4488
HP
3645{
3646
3e26416e 3647 s32 err = 0;
cf2b4488
HP
3648
3649 return err;
3650}
3651
3e26416e 3652static s32 wl_dongle_up(struct net_device *ndev, u32 up)
cf2b4488 3653{
3e26416e 3654 s32 err = 0;
cf2b4488 3655
76c06459
JC
3656 err = wl_dev_ioctl(ndev, WLC_UP, &up, sizeof(up));
3657 if (unlikely(err)) {
f4528696 3658 WL_ERR("WLC_UP error (%d)\n", err);
cf2b4488
HP
3659 }
3660 return err;
3661}
3662
3e26416e 3663static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
cf2b4488 3664{
3e26416e 3665 s32 err = 0;
cf2b4488 3666
76c06459
JC
3667 err = wl_dev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode));
3668 if (unlikely(err)) {
f4528696 3669 WL_ERR("WLC_SET_PM error (%d)\n", err);
cf2b4488
HP
3670 }
3671 return err;
3672}
3673
3e26416e 3674static s32
66cbd3ab 3675wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
cf2b4488 3676{
562c8850 3677 s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
cf2b4488 3678 '\0' + bitvec */
3e26416e 3679 s32 err = 0;
cf2b4488
HP
3680
3681 /* Match Host and Dongle rx alignment */
3682 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
3683 sizeof(iovbuf));
76c06459
JC
3684 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3685 if (unlikely(err)) {
f4528696 3686 WL_ERR("txglomalign error (%d)\n", err);
cf2b4488
HP
3687 goto dongle_glom_out;
3688 }
3689 /* disable glom option per default */
3690 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
76c06459
JC
3691 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3692 if (unlikely(err)) {
f4528696 3693 WL_ERR("txglom error (%d)\n", err);
cf2b4488
HP
3694 goto dongle_glom_out;
3695 }
3696dongle_glom_out:
3697 return err;
3698}
3699
3e26416e
GKH
3700static s32
3701wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
cf2b4488 3702{
562c8850 3703 s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
cf2b4488 3704 '\0' + bitvec */
3e26416e 3705 s32 err = 0;
cf2b4488
HP
3706
3707 /* Set ARP offload */
3708 bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
76c06459
JC
3709 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3710 if (err) {
cf2b4488 3711 if (err == -EOPNOTSUPP)
f4528696 3712 WL_INFO("arpoe is not supported\n");
cf2b4488 3713 else
f4528696 3714 WL_ERR("arpoe error (%d)\n", err);
cf2b4488
HP
3715
3716 goto dongle_offload_out;
3717 }
3718 bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
76c06459
JC
3719 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3720 if (err) {
cf2b4488 3721 if (err == -EOPNOTSUPP)
f4528696 3722 WL_INFO("arp_ol is not supported\n");
cf2b4488 3723 else
f4528696 3724 WL_ERR("arp_ol error (%d)\n", err);
cf2b4488
HP
3725
3726 goto dongle_offload_out;
3727 }
3728
3729dongle_offload_out:
3730 return err;
3731}
3732
3e26416e 3733static s32 wl_pattern_atoh(s8 *src, s8 *dst)
cf2b4488 3734{
cf2b4488
HP
3735 int i;
3736 if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
f4528696 3737 WL_ERR("Mask invalid format. Needs to start with 0x\n");
cf2b4488
HP
3738 return -1;
3739 }
3740 src = src + 2; /* Skip past 0x */
3741 if (strlen(src) % 2 != 0) {
f4528696 3742 WL_ERR("Mask invalid format. Needs to be of even length\n");
cf2b4488
HP
3743 return -1;
3744 }
3745 for (i = 0; *src != '\0'; i++) {
3746 char num[3];
3747 strncpy(num, src, 2);
3748 num[2] = '\0';
d5642d3b 3749 dst[i] = (u8) simple_strtoul(num, NULL, 16);
cf2b4488
HP
3750 src += 2;
3751 }
3752 return i;
3753}
3754
3e26416e 3755static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
cf2b4488 3756{
562c8850 3757 s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
cf2b4488 3758 '\0' + bitvec */
562c8850 3759 const s8 *str;
cf2b4488
HP
3760 struct wl_pkt_filter pkt_filter;
3761 struct wl_pkt_filter *pkt_filterp;
3e26416e
GKH
3762 s32 buf_len;
3763 s32 str_len;
66cbd3ab
GKH
3764 u32 mask_size;
3765 u32 pattern_size;
562c8850 3766 s8 buf[256];
3e26416e 3767 s32 err = 0;
cf2b4488
HP
3768
3769/* add a default packet filter pattern */
3770 str = "pkt_filter_add";
3771 str_len = strlen(str);
3772 strncpy(buf, str, str_len);
3773 buf[str_len] = '\0';
3774 buf_len = str_len + 1;
3775
3776 pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
3777
3778 /* Parse packet filter id. */
29750b90 3779 pkt_filter.id = cpu_to_le32(100);
cf2b4488
HP
3780
3781 /* Parse filter polarity. */
29750b90 3782 pkt_filter.negate_match = cpu_to_le32(0);
cf2b4488
HP
3783
3784 /* Parse filter type. */
29750b90 3785 pkt_filter.type = cpu_to_le32(0);
cf2b4488
HP
3786
3787 /* Parse pattern filter offset. */
29750b90 3788 pkt_filter.u.pattern.offset = cpu_to_le32(0);
cf2b4488
HP
3789
3790 /* Parse pattern filter mask. */
29750b90
SF
3791 mask_size = cpu_to_le32(wl_pattern_atoh("0xff",
3792 (char *)pkt_filterp->u.pattern.
3793 mask_and_pattern));
cf2b4488
HP
3794
3795 /* Parse pattern filter pattern. */
29750b90
SF
3796 pattern_size = cpu_to_le32(wl_pattern_atoh("0x00",
3797 (char *)&pkt_filterp->u.
3798 pattern.
3799 mask_and_pattern
3800 [mask_size]));
cf2b4488
HP
3801
3802 if (mask_size != pattern_size) {
f4528696 3803 WL_ERR("Mask and pattern not the same size\n");
cf2b4488
HP
3804 err = -EINVAL;
3805 goto dongle_filter_out;
3806 }
3807
3808 pkt_filter.u.pattern.size_bytes = mask_size;
3809 buf_len += WL_PKT_FILTER_FIXED_LEN;
3810 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
3811
3812 /* Keep-alive attributes are set in local
3813 * variable (keep_alive_pkt), and
3814 * then memcpy'ed into buffer (keep_alive_pktp) since there is no
3815 * guarantee that the buffer is properly aligned.
3816 */
3817 memcpy((char *)pkt_filterp, &pkt_filter,
3818 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
3819
76c06459
JC
3820 err = wl_dev_ioctl(ndev, WLC_SET_VAR, buf, buf_len);
3821 if (err) {
cf2b4488 3822 if (err == -EOPNOTSUPP) {
f4528696 3823 WL_INFO("filter not supported\n");
cf2b4488 3824 } else {
f4528696 3825 WL_ERR("filter (%d)\n", err);
cf2b4488
HP
3826 }
3827 goto dongle_filter_out;
3828 }
3829
3830 /* set mode to allow pattern */
3831 bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
3832 sizeof(iovbuf));
76c06459
JC
3833 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3834 if (err) {
cf2b4488 3835 if (err == -EOPNOTSUPP) {
f4528696 3836 WL_INFO("filter_mode not supported\n");
cf2b4488 3837 } else {
f4528696 3838 WL_ERR("filter_mode (%d)\n", err);
cf2b4488
HP
3839 }
3840 goto dongle_filter_out;
3841 }
3842
3843dongle_filter_out:
3844 return err;
3845}
3846#endif /* !EMBEDDED_PLATFORM */
3847
e494632e
SS
3848static s32 wl_dongle_eventmsg(struct net_device *ndev)
3849{
3850 s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
3851 '\0' + bitvec */
3852 s8 eventmask[WL_EVENTING_MASK_LEN];
3853 s32 err = 0;
3854
1ce4784e
SS
3855 WL_TRACE("Enter\n");
3856
e494632e
SS
3857 /* Setup event_msgs */
3858 bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
3859 sizeof(iovbuf));
3860 err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
3861 if (unlikely(err)) {
3862 WL_ERR("Get event_msgs error (%d)\n", err);
3863 goto dongle_eventmsg_out;
3864 }
3865 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
3866
3867 setbit(eventmask, WLC_E_SET_SSID);
3868 setbit(eventmask, WLC_E_ROAM);
3869 setbit(eventmask, WLC_E_PRUNE);
3870 setbit(eventmask, WLC_E_AUTH);
3871 setbit(eventmask, WLC_E_REASSOC);
3872 setbit(eventmask, WLC_E_REASSOC_IND);
3873 setbit(eventmask, WLC_E_DEAUTH_IND);
3874 setbit(eventmask, WLC_E_DISASSOC_IND);
3875 setbit(eventmask, WLC_E_DISASSOC);
3876 setbit(eventmask, WLC_E_JOIN);
3877 setbit(eventmask, WLC_E_ASSOC_IND);
3878 setbit(eventmask, WLC_E_PSK_SUP);
3879 setbit(eventmask, WLC_E_LINK);
3880 setbit(eventmask, WLC_E_NDIS_LINK);
3881 setbit(eventmask, WLC_E_MIC_ERROR);
3882 setbit(eventmask, WLC_E_PMKID_CACHE);
3883 setbit(eventmask, WLC_E_TXFAIL);
3884 setbit(eventmask, WLC_E_JOIN_START);
3885 setbit(eventmask, WLC_E_SCAN_COMPLETE);
3886
3887 bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
3888 sizeof(iovbuf));
3889 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3890 if (unlikely(err)) {
3891 WL_ERR("Set event_msgs error (%d)\n", err);
3892 goto dongle_eventmsg_out;
3893 }
3894
3895dongle_eventmsg_out:
1ce4784e 3896 WL_TRACE("Exit\n");
e494632e
SS
3897 return err;
3898}
3899
a1e962b6
SS
3900static s32
3901wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
3902{
3903 s8 iovbuf[32];
3904 s32 roamtrigger[2];
3905 s32 roam_delta[2];
3906 s32 err = 0;
3907
3908 /*
3909 * Setup timeout if Beacons are lost and roam is
3910 * off to report link down
3911 */
3912 if (roamvar) {
3913 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout,
3914 sizeof(bcn_timeout), iovbuf, sizeof(iovbuf));
3915 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3916 if (unlikely(err)) {
3917 WL_ERR("bcn_timeout error (%d)\n", err);
3918 goto dongle_rom_out;
3919 }
3920 }
3921
3922 /*
3923 * Enable/Disable built-in roaming to allow supplicant
3924 * to take care of roaming
3925 */
3926 WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
3927 bcm_mkiovar("roam_off", (char *)&roamvar,
3928 sizeof(roamvar), iovbuf, sizeof(iovbuf));
3929 err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
3930 if (unlikely(err)) {
3931 WL_ERR("roam_off error (%d)\n", err);
3932 goto dongle_rom_out;
3933 }
3934
3935 roamtrigger[0] = WL_ROAM_TRIGGER_LEVEL;
3936 roamtrigger[1] = WLC_BAND_ALL;
3937 err = wl_dev_ioctl(ndev, WLC_SET_ROAM_TRIGGER,
3938 (void *)roamtrigger, sizeof(roamtrigger));
3939 if (unlikely(err)) {
3940 WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
3941 goto dongle_rom_out;
3942 }
3943
3944 roam_delta[0] = WL_ROAM_DELTA;
3945 roam_delta[1] = WLC_BAND_ALL;
3946 err = wl_dev_ioctl(ndev, WLC_SET_ROAM_DELTA,
3947 (void *)roam_delta, sizeof(roam_delta));
3948 if (unlikely(err)) {
3949 WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
3950 goto dongle_rom_out;
3951 }
3952
3953dongle_rom_out:
3954 return err;
3955}
3956
e4dd6325
SS
3957static s32
3958wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
3959 s32 scan_unassoc_time, s32 scan_passive_time)
3960{
3961 s32 err = 0;
3962
3963 err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
3964 sizeof(scan_assoc_time));
3965 if (err) {
3966 if (err == -EOPNOTSUPP)
3967 WL_INFO("Scan assoc time is not supported\n");
3968 else
3969 WL_ERR("Scan assoc time error (%d)\n", err);
3970 goto dongle_scantime_out;
3971 }
3972 err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
3973 sizeof(scan_unassoc_time));
3974 if (err) {
3975 if (err == -EOPNOTSUPP)
3976 WL_INFO("Scan unassoc time is not supported\n");
3977 else
3978 WL_ERR("Scan unassoc time error (%d)\n", err);
3979 goto dongle_scantime_out;
3980 }
3981
3982 err = wl_dev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, &scan_passive_time,
3983 sizeof(scan_passive_time));
3984 if (err) {
3985 if (err == -EOPNOTSUPP)
3986 WL_INFO("Scan passive time is not supported\n");
3987 else
3988 WL_ERR("Scan passive time error (%d)\n", err);
3989 goto dongle_scantime_out;
3990 }
3991
3992dongle_scantime_out:
3993 return err;
3994}
3995
3e26416e 3996s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
cf2b4488
HP
3997{
3998#ifndef DHD_SDALIGN
3999#define DHD_SDALIGN 32
4000#endif
4001 struct net_device *ndev;
4002 struct wireless_dev *wdev;
3e26416e 4003 s32 err = 0;
cf2b4488
HP
4004
4005 if (wl->dongle_up)
4006 return err;
4007
4008 ndev = wl_to_ndev(wl);
4009 wdev = ndev->ieee80211_ptr;
4010 if (need_lock)
4011 rtnl_lock();
4012
4013#ifndef EMBEDDED_PLATFORM
76c06459
JC
4014 err = wl_dongle_up(ndev, 0);
4015 if (unlikely(err))
cf2b4488 4016 goto default_conf_out;
76c06459
JC
4017 err = wl_dongle_country(ndev, 0);
4018 if (unlikely(err))
cf2b4488 4019 goto default_conf_out;
76c06459
JC
4020 err = wl_dongle_power(ndev, PM_FAST);
4021 if (unlikely(err))
cf2b4488 4022 goto default_conf_out;
76c06459 4023 err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
76c06459 4024 if (unlikely(err))
cf2b4488 4025 goto default_conf_out;
e4dd6325 4026
cf2b4488
HP
4027 wl_dongle_offload(ndev, 1, 0xf);
4028 wl_dongle_filter(ndev, 1);
e4dd6325
SS
4029#endif /* !EMBEDDED_PLATFORM */
4030
4031 wl_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
4032 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
cf2b4488 4033
e494632e 4034 err = wl_dongle_eventmsg(ndev);
a1e962b6
SS
4035 if (unlikely(err))
4036 goto default_conf_out;
4037 err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
e494632e
SS
4038 if (unlikely(err))
4039 goto default_conf_out;
cf2b4488
HP
4040 err = wl_dongle_mode(ndev, wdev->iftype);
4041 if (unlikely(err && err != -EINPROGRESS))
4042 goto default_conf_out;
76c06459
JC
4043 err = wl_dongle_probecap(wl);
4044 if (unlikely(err))
cf2b4488
HP
4045 goto default_conf_out;
4046
4047 /* -EINPROGRESS: Call commit handler */
4048
4049default_conf_out:
4050 if (need_lock)
4051 rtnl_unlock();
4052
0f0881b0 4053 wl->dongle_up = true;
cf2b4488
HP
4054
4055 return err;
4056
4057}
4058
3e26416e 4059static s32 wl_update_wiphybands(struct wl_priv *wl)
cf2b4488
HP
4060{
4061 struct wiphy *wiphy;
3e26416e 4062 s32 phy_list;
562c8850 4063 s8 phy;
3e26416e 4064 s32 err = 0;
cf2b4488 4065
76c06459
JC
4066 err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_PHYLIST, &phy_list,
4067 sizeof(phy_list));
4068 if (unlikely(err)) {
f4528696 4069 WL_ERR("error (%d)\n", err);
cf2b4488
HP
4070 return err;
4071 }
4072
4073 phy = ((char *)&phy_list)[1];
1ce4784e 4074 WL_INFO("%c phy\n", phy);
cf2b4488
HP
4075 if (phy == 'n' || phy == 'a') {
4076 wiphy = wl_to_wiphy(wl);
4077 wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
4078 }
4079
4080 return err;
4081}
4082
3e26416e 4083static s32 __wl_cfg80211_up(struct wl_priv *wl)
cf2b4488 4084{
3e26416e 4085 s32 err = 0;
cf2b4488 4086
65dd4892
SS
4087 set_bit(WL_STATUS_READY, &wl->status);
4088
cd389a34 4089 wl_debugfs_add_netdev_params(wl);
4090
0965ae88 4091 err = wl_config_dongle(wl, false);
76c06459 4092 if (unlikely(err))
cf2b4488
HP
4093 return err;
4094
4095 wl_invoke_iscan(wl);
65dd4892 4096
cf2b4488
HP
4097 return err;
4098}
4099
3e26416e 4100static s32 __wl_cfg80211_down(struct wl_priv *wl)
cf2b4488 4101{
cf2b4488
HP
4102 set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
4103 wl_term_iscan(wl);
4104 if (wl->scan_request) {
65dd4892
SS
4105 cfg80211_scan_done(wl->scan_request, true);
4106 /* May need to perform this to cover rmmod */
4107 /* wl_set_mpc(wl_to_ndev(wl), 1); */
cf2b4488
HP
4108 wl->scan_request = NULL;
4109 }
4110 clear_bit(WL_STATUS_READY, &wl->status);
4111 clear_bit(WL_STATUS_SCANNING, &wl->status);
4112 clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
65dd4892 4113 clear_bit(WL_STATUS_CONNECTING, &wl->status);
cf2b4488
HP
4114 clear_bit(WL_STATUS_CONNECTED, &wl->status);
4115
cd389a34 4116 wl_debugfs_remove_netdev(wl);
4117
65dd4892 4118 return 0;
cf2b4488
HP
4119}
4120
3e26416e 4121s32 wl_cfg80211_up(void)
cf2b4488
HP
4122{
4123 struct wl_priv *wl;
3e26416e 4124 s32 err = 0;
cf2b4488
HP
4125
4126 wl = WL_PRIV_GET();
4127 mutex_lock(&wl->usr_sync);
4128 err = __wl_cfg80211_up(wl);
4129 mutex_unlock(&wl->usr_sync);
4130
4131 return err;
4132}
4133
3e26416e 4134s32 wl_cfg80211_down(void)
cf2b4488
HP
4135{
4136 struct wl_priv *wl;
3e26416e 4137 s32 err = 0;
cf2b4488
HP
4138
4139 wl = WL_PRIV_GET();
4140 mutex_lock(&wl->usr_sync);
4141 err = __wl_cfg80211_down(wl);
4142 mutex_unlock(&wl->usr_sync);
4143
4144 return err;
4145}
4146
3e26416e 4147static s32 wl_dongle_probecap(struct wl_priv *wl)
cf2b4488 4148{
3e26416e 4149 s32 err = 0;
cf2b4488 4150
76c06459
JC
4151 err = wl_update_wiphybands(wl);
4152 if (unlikely(err))
cf2b4488
HP
4153 return err;
4154
4155 return err;
4156}
4157
3e26416e 4158static void *wl_read_prof(struct wl_priv *wl, s32 item)
cf2b4488
HP
4159{
4160 switch (item) {
4161 case WL_PROF_SEC:
4162 return &wl->profile->sec;
cf2b4488
HP
4163 case WL_PROF_BSSID:
4164 return &wl->profile->bssid;
4165 case WL_PROF_SSID:
4166 return &wl->profile->ssid;
4167 }
f4528696 4168 WL_ERR("invalid item (%d)\n", item);
cf2b4488
HP
4169 return NULL;
4170}
4171
3e26416e 4172static s32
cf2b4488 4173wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
3e26416e 4174 s32 item)
cf2b4488 4175{
3e26416e 4176 s32 err = 0;
cf2b4488
HP
4177 struct wlc_ssid *ssid;
4178
4179 switch (item) {
4180 case WL_PROF_SSID:
4181 ssid = (wlc_ssid_t *) data;
4182 memset(wl->profile->ssid.SSID, 0,
4183 sizeof(wl->profile->ssid.SSID));
4184 memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
4185 wl->profile->ssid.SSID_len = ssid->SSID_len;
4186 break;
4187 case WL_PROF_BSSID:
4188 if (data)
b8d63078 4189 memcpy(wl->profile->bssid, data, ETH_ALEN);
cf2b4488 4190 else
b8d63078 4191 memset(wl->profile->bssid, 0, ETH_ALEN);
cf2b4488
HP
4192 break;
4193 case WL_PROF_SEC:
4194 memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
4195 break;
1e0645c3 4196 case WL_PROF_BEACONINT:
4197 wl->profile->beacon_interval = *(u16 *)data;
4198 break;
4199 case WL_PROF_DTIMPERIOD:
4200 wl->profile->dtim_period = *(u8 *)data;
cf2b4488
HP
4201 break;
4202 default:
f4528696 4203 WL_ERR("unsupported item (%d)\n", item);
cf2b4488
HP
4204 err = -EOPNOTSUPP;
4205 break;
4206 }
4207
4208 return err;
4209}
4210
cf2b4488
HP
4211static bool wl_is_ibssmode(struct wl_priv *wl)
4212{
4213 return wl->conf->mode == WL_MODE_IBSS;
4214}
4215
5dc56c9f 4216static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
cf2b4488
HP
4217{
4218 struct wl_ie *ie = wl_to_ie(wl);
3e26416e 4219 s32 err = 0;
cf2b4488
HP
4220
4221 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
f4528696 4222 WL_ERR("ei crosses buffer boundary\n");
cf2b4488
HP
4223 return -ENOSPC;
4224 }
4225 ie->buf[ie->offset] = t;
4226 ie->buf[ie->offset + 1] = l;
4227 memcpy(&ie->buf[ie->offset + 2], v, l);
4228 ie->offset += l + 2;
4229
4230 return err;
4231}
4232
cf2b4488 4233
cf2b4488
HP
4234static void wl_link_down(struct wl_priv *wl)
4235{
e494632e
SS
4236 struct net_device *dev = NULL;
4237 s32 err = 0;
cf2b4488 4238
1ce4784e 4239 WL_TRACE("Enter\n");
e494632e
SS
4240 clear_bit(WL_STATUS_CONNECTED, &wl->status);
4241
4242 if (wl->link_up) {
4243 dev = wl_to_ndev(wl);
4244 WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
4245 err = wl_dev_ioctl(dev, WLC_DISASSOC, NULL, 0);
4246 if (unlikely(err))
4247 WL_ERR("WLC_DISASSOC failed (%d)\n", err);
4248 wl->link_up = false;
4249 }
1ce4784e 4250 WL_TRACE("Exit\n");
cf2b4488
HP
4251}
4252
4253static void wl_lock_eq(struct wl_priv *wl)
4254{
4255 spin_lock_irq(&wl->eq_lock);
4256}
4257
4258static void wl_unlock_eq(struct wl_priv *wl)
4259{
4260 spin_unlock_irq(&wl->eq_lock);
4261}
4262
4263static void wl_init_eq_lock(struct wl_priv *wl)
4264{
4265 spin_lock_init(&wl->eq_lock);
4266}
4267
66cbd3ab 4268static void wl_delay(u32 ms)
cf2b4488
HP
4269{
4270 if (ms < 1000 / HZ) {
4271 cond_resched();
4272 mdelay(ms);
4273 } else {
4274 msleep(ms);
4275 }
4276}
4277
4278static void wl_set_drvdata(struct wl_dev *dev, void *data)
4279{
4280 dev->driver_data = data;
4281}
4282
4283static void *wl_get_drvdata(struct wl_dev *dev)
4284{
4285 return dev->driver_data;
4286}
4287
3e26416e 4288s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
cf2b4488
HP
4289{
4290 const struct firmware *fw_entry;
4291 struct wl_priv *wl;
4292
4293 wl = WL_PRIV_GET();
4294
4295 fw_entry = wl->fw->fw_entry;
4296
4297 if (fw_entry->size < wl->fw->ptr + size)
4298 size = fw_entry->size - wl->fw->ptr;
4299
4300 memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
4301 wl->fw->ptr += size;
4302 return size;
4303}
4304
4305void wl_cfg80211_release_fw(void)
4306{
4307 struct wl_priv *wl;
4308
4309 wl = WL_PRIV_GET();
4310 release_firmware(wl->fw->fw_entry);
4311 wl->fw->ptr = 0;
4312}
4313
562c8850 4314void *wl_cfg80211_request_fw(s8 *file_name)
cf2b4488
HP
4315{
4316 struct wl_priv *wl;
4317 const struct firmware *fw_entry = NULL;
3e26416e 4318 s32 err = 0;
cf2b4488 4319
1ce4784e 4320 WL_INFO("file name : \"%s\"\n", file_name);
cf2b4488
HP
4321 wl = WL_PRIV_GET();
4322
4323 if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
76c06459
JC
4324 err = request_firmware(&wl->fw->fw_entry, file_name,
4325 &wl_cfg80211_get_sdio_func()->dev);
4326 if (unlikely(err)) {
f4528696 4327 WL_ERR("Could not download fw (%d)\n", err);
cf2b4488
HP
4328 goto req_fw_out;
4329 }
4330 set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
4331 fw_entry = wl->fw->fw_entry;
4332 if (fw_entry) {
1ce4784e 4333 WL_INFO("fw size (%zd), data (%p)\n",
f4528696 4334 fw_entry->size, fw_entry->data);
cf2b4488
HP
4335 }
4336 } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
76c06459
JC
4337 err = request_firmware(&wl->fw->fw_entry, file_name,
4338 &wl_cfg80211_get_sdio_func()->dev);
4339 if (unlikely(err)) {
f4528696 4340 WL_ERR("Could not download nvram (%d)\n", err);
cf2b4488
HP
4341 goto req_fw_out;
4342 }
4343 set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
4344 fw_entry = wl->fw->fw_entry;
4345 if (fw_entry) {
1ce4784e 4346 WL_INFO("nvram size (%zd), data (%p)\n",
f4528696 4347 fw_entry->size, fw_entry->data);
cf2b4488
HP
4348 }
4349 } else {
1ce4784e 4350 WL_INFO("Downloading already done. Nothing to do more\n");
cf2b4488
HP
4351 err = -EPERM;
4352 }
4353
4354req_fw_out:
4355 if (unlikely(err)) {
4356 return NULL;
4357 }
4358 wl->fw->ptr = 0;
4359 return (void *)fw_entry->data;
4360}
4361
562c8850 4362s8 *wl_cfg80211_get_fwname(void)
cf2b4488
HP
4363{
4364 struct wl_priv *wl;
4365
4366 wl = WL_PRIV_GET();
4367 strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
4368 return wl->fw->fw_name;
4369}
4370
562c8850 4371s8 *wl_cfg80211_get_nvramname(void)
cf2b4488
HP
4372{
4373 struct wl_priv *wl;
4374
4375 wl = WL_PRIV_GET();
4376 strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
4377 return wl->fw->nvram_name;
4378}
fb693a71 4379
4380static void wl_set_mpc(struct net_device *ndev, int mpc)
4381{
4382 s32 err = 0;
9446af06 4383 struct wl_priv *wl = ndev_to_wl(ndev);
fb693a71 4384
9446af06
SS
4385 if (test_bit(WL_STATUS_READY, &wl->status)) {
4386 err = wl_dev_intvar_set(ndev, "mpc", mpc);
4387 if (unlikely(err)) {
4388 WL_ERR("fail to set mpc\n");
4389 return;
4390 }
4391 WL_INFO("MPC : %d\n", mpc);
fb693a71 4392 }
fb693a71 4393}
cd389a34 4394
4395static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
4396{
4397 char buf[10+IFNAMSIZ];
4398 struct dentry *fd;
4399 s32 err = 0;
4400
4401 sprintf(buf, "netdev:%s", wl_to_ndev(wl)->name);
4402 wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
4403
4404 fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
4405 (u16 *)&wl->profile->beacon_interval);
4406 if (!fd) {
4407 err = -ENOMEM;
4408 goto err_out;
4409 }
4410
4411 fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
4412 (u8 *)&wl->profile->dtim_period);
4413 if (!fd) {
4414 err = -ENOMEM;
4415 goto err_out;
4416 }
4417
4418err_out:
4419 return err;
4420}
4421
4422static void wl_debugfs_remove_netdev(struct wl_priv *wl)
4423{
4424 debugfs_remove_recursive(wl->debugfsdir);
4425 wl->debugfsdir = NULL;
4426}
This page took 0.343791 seconds and 5 git commands to generate.