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