aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/wl_cfg80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c7330
1 files changed, 7330 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
new file mode 100644
index 00000000000..daa7d2605aa
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -0,0 +1,7330 @@
1/*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 1999-2011, 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.4.1.2.14 2011/02/09 01:40:07 Exp $
25 */
26
27#include <typedefs.h>
28#include <linuxver.h>
29#include <osl.h>
30#include <linux/kernel.h>
31
32#include <bcmutils.h>
33#include <bcmwifi.h>
34#include <bcmendian.h>
35#include <proto/ethernet.h>
36#include <proto/802.11.h>
37#include <linux/if_arp.h>
38#include <asm/uaccess.h>
39
40#include <dngl_stats.h>
41#include <dhd.h>
42#include <dhdioctl.h>
43#include <wlioctl.h>
44
45#include <proto/ethernet.h>
46#include <dngl_stats.h>
47#include <dhd.h>
48#include <linux/kernel.h>
49#include <linux/kthread.h>
50#include <linux/netdevice.h>
51#include <linux/sched.h>
52#include <linux/etherdevice.h>
53#include <linux/wireless.h>
54#include <linux/ieee80211.h>
55#include <linux/wait.h>
56#include <net/cfg80211.h>
57
58#include <net/rtnetlink.h>
59#include <linux/mmc/sdio_func.h>
60#include <linux/firmware.h>
61#include <bcmsdbus.h>
62
63#include <wlioctl.h>
64#include <wldev_common.h>
65#include <wl_cfg80211.h>
66#include <wl_cfgp2p.h>
67
68static struct sdio_func *cfg80211_sdio_func;
69static struct wl_priv *wlcfg_drv_priv;
70
71u32 wl_dbg_level = WL_DBG_ERR;
72
73#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
74#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
75#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
76#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
77#define MAX_WAIT_TIME 1500
78static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
79
80#define COEX_DHCP
81
82#if defined(COEX_DHCP)
83#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG
84 * suppression
85 */
86#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority
87 * to max, caution: -not fair to sco
88 */
89#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority
90 * suppression
91 */
92#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion
93 * is (timeout)
94 */
95enum wl_cfg80211_btcoex_status {
96 BT_DHCP_IDLE,
97 BT_DHCP_START,
98 BT_DHCP_OPPR_WIN,
99 BT_DHCP_FLAG_FORCE_TIMEOUT
100};
101
102static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
103static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
104#endif
105
106/* This is to override regulatory domains defined in cfg80211 module (reg.c)
107 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
108 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
109 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
110 * All the chnages in world regulatory domain are to be done here.
111 */
112static const struct ieee80211_regdomain brcm_regdom = {
113 .n_reg_rules = 5,
114 .alpha2 = "99",
115 .reg_rules = {
116 /* IEEE 802.11b/g, channels 1..11 */
117 REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
118 /* IEEE 802.11b/g, channels 12..13. No HT40
119 * channel fits here.
120 */
121 REG_RULE(2467-10, 2472+10, 20, 6, 20,
122 NL80211_RRF_PASSIVE_SCAN |
123 NL80211_RRF_NO_IBSS),
124 /* IEEE 802.11 channel 14 - Only JP enables
125 * this and for 802.11b only
126 */
127 REG_RULE(2484-10, 2484+10, 20, 6, 20,
128 NL80211_RRF_PASSIVE_SCAN |
129 NL80211_RRF_NO_IBSS |
130 NL80211_RRF_NO_OFDM),
131 /* IEEE 802.11a, channel 36..64 */
132 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
133 /* IEEE 802.11a, channel 100..165 */
134 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
135};
136
137
138/* Data Element Definitions */
139#define WPS_ID_CONFIG_METHODS 0x1008
140#define WPS_ID_REQ_TYPE 0x103A
141#define WPS_ID_DEVICE_NAME 0x1011
142#define WPS_ID_VERSION 0x104A
143#define WPS_ID_DEVICE_PWD_ID 0x1012
144#define WPS_ID_REQ_DEV_TYPE 0x106A
145#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
146#define WPS_ID_PRIM_DEV_TYPE 0x1054
147
148/* Device Password ID */
149#define DEV_PW_DEFAULT 0x0000
150#define DEV_PW_USER_SPECIFIED 0x0001,
151#define DEV_PW_MACHINE_SPECIFIED 0x0002
152#define DEV_PW_REKEY 0x0003
153#define DEV_PW_PUSHBUTTON 0x0004
154#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
155
156/* Config Methods */
157#define WPS_CONFIG_USBA 0x0001
158#define WPS_CONFIG_ETHERNET 0x0002
159#define WPS_CONFIG_LABEL 0x0004
160#define WPS_CONFIG_DISPLAY 0x0008
161#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
162#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
163#define WPS_CONFIG_NFC_INTERFACE 0x0040
164#define WPS_CONFIG_PUSHBUTTON 0x0080
165#define WPS_CONFIG_KEYPAD 0x0100
166#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
167#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
168#define WPS_CONFIG_VIRT_DISPLAY 0x2008
169#define WPS_CONFIG_PHY_DISPLAY 0x4008
170
171/*
172 * cfg80211_ops api/callback list
173 */
174static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
175 const struct ether_addr *sa, const struct ether_addr *bssid,
176 u8 **pheader, u32 *body_len, u8 *pbody);
177static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
178 struct cfg80211_scan_request *request,
179 struct cfg80211_ssid *this_ssid);
180static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
181 struct cfg80211_scan_request *request);
182static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
183static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
184 struct cfg80211_ibss_params *params);
185static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
186 struct net_device *dev);
187static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
188 struct net_device *dev, u8 *mac,
189 struct station_info *sinfo);
190static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
191 struct net_device *dev, bool enabled,
192 s32 timeout);
193static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
194 struct cfg80211_connect_params *sme);
195static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
196 u16 reason_code);
197static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
198 enum nl80211_tx_power_setting type,
199 s32 dbm);
200static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
201static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
202 struct net_device *dev,
203 u8 key_idx, bool unicast, bool multicast);
204static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
205 u8 key_idx, bool pairwise, const u8 *mac_addr,
206 struct key_params *params);
207static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
208 u8 key_idx, bool pairwise, const u8 *mac_addr);
209static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
210 u8 key_idx, bool pairwise, const u8 *mac_addr,
211 void *cookie, void (*callback) (void *cookie,
212 struct key_params *params));
213static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
214 struct net_device *dev, u8 key_idx);
215static s32 wl_cfg80211_resume(struct wiphy *wiphy);
216#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
217static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
218#else
219static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
220#endif
221static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
222 struct cfg80211_pmksa *pmksa);
223static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
224 struct cfg80211_pmksa *pmksa);
225static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
226 struct net_device *dev);
227static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted);
228/*
229 * event & event Q handlers for cfg80211 interfaces
230 */
231static s32 wl_create_event_handler(struct wl_priv *wl);
232static void wl_destroy_event_handler(struct wl_priv *wl);
233static s32 wl_event_handler(void *data);
234static void wl_init_eq(struct wl_priv *wl);
235static void wl_flush_eq(struct wl_priv *wl);
236static unsigned long wl_lock_eq(struct wl_priv *wl);
237static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags);
238static void wl_init_eq_lock(struct wl_priv *wl);
239static void wl_init_event_handler(struct wl_priv *wl);
240static struct wl_event_q *wl_deq_event(struct wl_priv *wl);
241static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type,
242 const wl_event_msg_t *msg, void *data);
243static void wl_put_event(struct wl_event_q *e);
244static void wl_wakeup_event(struct wl_priv *wl);
245static s32 wl_notify_connect_status(struct wl_priv *wl,
246 struct net_device *ndev,
247 const wl_event_msg_t *e, void *data);
248static s32 wl_notify_roaming_status(struct wl_priv *wl,
249 struct net_device *ndev,
250 const wl_event_msg_t *e, void *data);
251static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
252 const wl_event_msg_t *e, void *data);
253static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
254 const wl_event_msg_t *e, void *data, bool completed);
255static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
256 const wl_event_msg_t *e, void *data);
257static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
258 const wl_event_msg_t *e, void *data);
259/*
260 * register/deregister sdio function
261 */
262struct sdio_func *wl_cfg80211_get_sdio_func(void);
263static void wl_clear_sdio_func(void);
264
265/*
266 * ioctl utilites
267 */
268static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
269 s32 buf_len);
270static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
271 s8 *buf, s32 len);
272static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
273static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
274 s32 *retval);
275
276/*
277 * cfg80211 set_wiphy_params utilities
278 */
279static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
280static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
281static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
282
283/*
284 * wl profile utilities
285 */
286static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
287 void *data, s32 item);
288static void *wl_read_prof(struct wl_priv *wl, s32 item);
289static void wl_init_prof(struct wl_priv *wl);
290
291/*
292 * cfg80211 connect utilites
293 */
294static s32 wl_set_wpa_version(struct net_device *dev,
295 struct cfg80211_connect_params *sme);
296static s32 wl_set_auth_type(struct net_device *dev,
297 struct cfg80211_connect_params *sme);
298static s32 wl_set_set_cipher(struct net_device *dev,
299 struct cfg80211_connect_params *sme);
300static s32 wl_set_key_mgmt(struct net_device *dev,
301 struct cfg80211_connect_params *sme);
302static s32 wl_set_set_sharedkey(struct net_device *dev,
303 struct cfg80211_connect_params *sme);
304static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev);
305static void wl_ch_to_chanspec(int ch,
306 struct wl_join_params *join_params, size_t *join_params_size);
307
308/*
309 * information element utilities
310 */
311static void wl_rst_ie(struct wl_priv *wl);
312static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v);
313static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
314static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
315static u32 wl_get_ielen(struct wl_priv *wl);
316
317static s32 wl_mode_to_nl80211_iftype(s32 mode);
318
319static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
320static void wl_free_wdev(struct wl_priv *wl);
321
322static s32 wl_inform_bss(struct wl_priv *wl);
323static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
324static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
325
326static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
327 u8 key_idx, const u8 *mac_addr,
328 struct key_params *params);
329/*
330 * key indianess swap utilities
331 */
332static void swap_key_from_BE(struct wl_wsec_key *key);
333static void swap_key_to_BE(struct wl_wsec_key *key);
334
335/*
336 * wl_priv memory init/deinit utilities
337 */
338static s32 wl_init_priv_mem(struct wl_priv *wl);
339static void wl_deinit_priv_mem(struct wl_priv *wl);
340
341static void wl_delay(u32 ms);
342
343/*
344 * ibss mode utilities
345 */
346static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev);
347static __used bool wl_is_ibssstarter(struct wl_priv *wl);
348
349/*
350 * dongle up/down , default configuration utilities
351 */
352static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
353static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev);
354static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
355static void wl_link_up(struct wl_priv *wl);
356static void wl_link_down(struct wl_priv *wl);
357static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
358static s32 __wl_cfg80211_up(struct wl_priv *wl);
359static s32 __wl_cfg80211_down(struct wl_priv *wl);
360static s32 wl_dongle_probecap(struct wl_priv *wl);
361static void wl_init_conf(struct wl_conf *conf);
362static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
363
364/*
365 * dongle configuration utilities
366 */
367#ifndef EMBEDDED_PLATFORM
368static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
369static s32 wl_dongle_up(struct net_device *ndev, u32 up);
370static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
371static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
372 u32 dongle_align);
373static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
374 u32 bcn_timeout);
375static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
376 s32 scan_unassoc_time);
377static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
378 s32 arp_ol);
379static s32 wl_pattern_atoh(s8 *src, s8 *dst);
380static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
381static s32 wl_update_wiphybands(struct wl_priv *wl);
382#endif /* !EMBEDDED_PLATFORM */
383static __used void wl_dongle_poweron(struct wl_priv *wl);
384static __used void wl_dongle_poweroff(struct wl_priv *wl);
385static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
386
387/*
388 * iscan handler
389 */
390static void wl_iscan_timer(unsigned long data);
391static void wl_term_iscan(struct wl_priv *wl);
392static s32 wl_init_scan(struct wl_priv *wl);
393static s32 wl_iscan_thread(void *data);
394static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
395 u16 action);
396static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request);
397static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan);
398static s32 wl_invoke_iscan(struct wl_priv *wl);
399static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
400 struct wl_scan_results **bss_list);
401static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted);
402static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan);
403static s32 wl_iscan_done(struct wl_priv *wl);
404static s32 wl_iscan_pending(struct wl_priv *wl);
405static s32 wl_iscan_inprogress(struct wl_priv *wl);
406static s32 wl_iscan_aborted(struct wl_priv *wl);
407
408/*
409 * fw/nvram downloading handler
410 */
411static void wl_init_fw(struct wl_fw_ctrl *fw);
412
413/*
414 * find most significant bit set
415 */
416static __used u32 wl_find_msb(u16 bit16);
417
418/*
419 * update pmklist to dongle
420 */
421static __used s32 wl_update_pmklist(struct net_device *dev,
422 struct wl_pmk_list *pmk_list, s32 err);
423
424/*
425 * debufs support
426 */
427static int wl_debugfs_add_netdev_params(struct wl_priv *wl);
428static void wl_debugfs_remove_netdev(struct wl_priv *wl);
429
430/*
431 * rfkill support
432 */
433static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
434static int wl_rfkill_set(void *data, bool blocked);
435
436/*
437 * Some external functions, TODO: move them to dhd_linux.h
438 */
439int dhd_add_monitor(char *name, struct net_device **new_ndev);
440int dhd_del_monitor(struct net_device *ndev);
441int dhd_monitor_init(void *dhd_pub);
442int dhd_monitor_uninit(void);
443int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
444
445#define CHECK_SYS_UP(wlpriv) \
446do { \
447 if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \
448 WL_INFO(("device is not ready : status (%d)\n", \
449 (int)wlpriv->status)); \
450 return -EIO; \
451 } \
452} while (0)
453
454
455#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
456 (akm) == RSN_AKM_UNSPECIFIED || \
457 (akm) == RSN_AKM_PSK)
458
459
460extern int dhd_wait_pend8021x(struct net_device *dev);
461
462#if (WL_DBG_LEVEL > 0)
463#define WL_DBG_ESTR_MAX 50
464static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
465 "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND",
466 "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC",
467 "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END",
468 "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM",
469 "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH",
470 "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND",
471 "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND",
472 "PFN_NET_LOST",
473 "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START",
474 "IBSS_ASSOC",
475 "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT",
476 "PROBREQ_MSG",
477 "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED",
478 "EXCEEDED_MEDIUM_TIME", "ICV_ERROR",
479 "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE",
480 "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE",
481 "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG",
482 "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND",
483 "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED",
484 "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT",
485 "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE",
486 "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP",
487 "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE"
488};
489#endif /* WL_DBG_LEVEL */
490
491#define CHAN2G(_channel, _freq, _flags) { \
492 .band = IEEE80211_BAND_2GHZ, \
493 .center_freq = (_freq), \
494 .hw_value = (_channel), \
495 .flags = (_flags), \
496 .max_antenna_gain = 0, \
497 .max_power = 30, \
498}
499
500#define CHAN5G(_channel, _flags) { \
501 .band = IEEE80211_BAND_5GHZ, \
502 .center_freq = 5000 + (5 * (_channel)), \
503 .hw_value = (_channel), \
504 .flags = (_flags), \
505 .max_antenna_gain = 0, \
506 .max_power = 30, \
507}
508
509#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
510#define RATETAB_ENT(_rateid, _flags) \
511 { \
512 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
513 .hw_value = (_rateid), \
514 .flags = (_flags), \
515 }
516
517static struct ieee80211_rate __wl_rates[] = {
518 RATETAB_ENT(WLC_RATE_1M, 0),
519 RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
520 RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
521 RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
522 RATETAB_ENT(WLC_RATE_6M, 0),
523 RATETAB_ENT(WLC_RATE_9M, 0),
524 RATETAB_ENT(WLC_RATE_12M, 0),
525 RATETAB_ENT(WLC_RATE_18M, 0),
526 RATETAB_ENT(WLC_RATE_24M, 0),
527 RATETAB_ENT(WLC_RATE_36M, 0),
528 RATETAB_ENT(WLC_RATE_48M, 0),
529 RATETAB_ENT(WLC_RATE_54M, 0)
530};
531
532#define wl_a_rates (__wl_rates + 4)
533#define wl_a_rates_size 8
534#define wl_g_rates (__wl_rates + 0)
535#define wl_g_rates_size 12
536
537static struct ieee80211_channel __wl_2ghz_channels[] = {
538 CHAN2G(1, 2412, 0),
539 CHAN2G(2, 2417, 0),
540 CHAN2G(3, 2422, 0),
541 CHAN2G(4, 2427, 0),
542 CHAN2G(5, 2432, 0),
543 CHAN2G(6, 2437, 0),
544 CHAN2G(7, 2442, 0),
545 CHAN2G(8, 2447, 0),
546 CHAN2G(9, 2452, 0),
547 CHAN2G(10, 2457, 0),
548 CHAN2G(11, 2462, 0),
549 CHAN2G(12, 2467, 0),
550 CHAN2G(13, 2472, 0),
551 CHAN2G(14, 2484, 0)
552};
553
554static struct ieee80211_channel __wl_5ghz_a_channels[] = {
555 CHAN5G(34, 0), CHAN5G(36, 0),
556 CHAN5G(38, 0), CHAN5G(40, 0),
557 CHAN5G(42, 0), CHAN5G(44, 0),
558 CHAN5G(46, 0), CHAN5G(48, 0),
559 CHAN5G(52, 0), CHAN5G(56, 0),
560 CHAN5G(60, 0), CHAN5G(64, 0),
561 CHAN5G(100, 0), CHAN5G(104, 0),
562 CHAN5G(108, 0), CHAN5G(112, 0),
563 CHAN5G(116, 0), CHAN5G(120, 0),
564 CHAN5G(124, 0), CHAN5G(128, 0),
565 CHAN5G(132, 0), CHAN5G(136, 0),
566 CHAN5G(140, 0), CHAN5G(149, 0),
567 CHAN5G(153, 0), CHAN5G(157, 0),
568 CHAN5G(161, 0), CHAN5G(165, 0)
569};
570
571static struct ieee80211_supported_band __wl_band_2ghz = {
572 .band = IEEE80211_BAND_2GHZ,
573 .channels = __wl_2ghz_channels,
574 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
575 .bitrates = wl_g_rates,
576 .n_bitrates = wl_g_rates_size
577};
578
579static struct ieee80211_supported_band __wl_band_5ghz_a = {
580 .band = IEEE80211_BAND_5GHZ,
581 .channels = __wl_5ghz_a_channels,
582 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
583 .bitrates = wl_a_rates,
584 .n_bitrates = wl_a_rates_size
585};
586
587static const u32 __wl_cipher_suites[] = {
588 WLAN_CIPHER_SUITE_WEP40,
589 WLAN_CIPHER_SUITE_WEP104,
590 WLAN_CIPHER_SUITE_TKIP,
591 WLAN_CIPHER_SUITE_CCMP,
592 WLAN_CIPHER_SUITE_AES_CMAC,
593};
594
595/* There isn't a lot of sense in it, but you can transmit anything you like */
596static const struct ieee80211_txrx_stypes
597wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
598 [NL80211_IFTYPE_ADHOC] = {
599 .tx = 0xffff,
600 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
601 },
602 [NL80211_IFTYPE_STATION] = {
603 .tx = 0xffff,
604 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
605 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
606 },
607 [NL80211_IFTYPE_AP] = {
608 .tx = 0xffff,
609 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
610 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
611 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
612 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
613 BIT(IEEE80211_STYPE_AUTH >> 4) |
614 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
615 BIT(IEEE80211_STYPE_ACTION >> 4)
616 },
617 [NL80211_IFTYPE_AP_VLAN] = {
618 /* copy AP */
619 .tx = 0xffff,
620 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
621 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
622 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
623 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
624 BIT(IEEE80211_STYPE_AUTH >> 4) |
625 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
626 BIT(IEEE80211_STYPE_ACTION >> 4)
627 },
628 [NL80211_IFTYPE_P2P_CLIENT] = {
629 .tx = 0xffff,
630 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
631 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
632 },
633 [NL80211_IFTYPE_P2P_GO] = {
634 .tx = 0xffff,
635 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
636 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
637 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
638 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
639 BIT(IEEE80211_STYPE_AUTH >> 4) |
640 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
641 BIT(IEEE80211_STYPE_ACTION >> 4)
642 }
643};
644
645static void swap_key_from_BE(struct wl_wsec_key *key)
646{
647 key->index = htod32(key->index);
648 key->len = htod32(key->len);
649 key->algo = htod32(key->algo);
650 key->flags = htod32(key->flags);
651 key->rxiv.hi = htod32(key->rxiv.hi);
652 key->rxiv.lo = htod16(key->rxiv.lo);
653 key->iv_initialized = htod32(key->iv_initialized);
654}
655
656static void swap_key_to_BE(struct wl_wsec_key *key)
657{
658 key->index = dtoh32(key->index);
659 key->len = dtoh32(key->len);
660 key->algo = dtoh32(key->algo);
661 key->flags = dtoh32(key->flags);
662 key->rxiv.hi = dtoh32(key->rxiv.hi);
663 key->rxiv.lo = dtoh16(key->rxiv.lo);
664 key->iv_initialized = dtoh32(key->iv_initialized);
665}
666
667/* For debug: Dump the contents of the encoded wps ie buffe */
668static void
669wl_validate_wps_ie(char *wps_ie, bool *pbc)
670{
671 #define WPS_IE_FIXED_LEN 6
672 u16 len = (u16) wps_ie[TLV_LEN_OFF];
673 u8 *subel = wps_ie+ WPS_IE_FIXED_LEN;
674 u16 subelt_id;
675 u16 subelt_len;
676 u16 val;
677 u8 *valptr = (uint8*) &val;
678
679 WL_DBG(("wps_ie len=%d\n", len));
680
681 len -= 4; /* for the WPS IE's OUI, oui_type fields */
682
683 while (len >= 4) { /* must have attr id, attr len fields */
684 valptr[0] = *subel++;
685 valptr[1] = *subel++;
686 subelt_id = HTON16(val);
687
688 valptr[0] = *subel++;
689 valptr[1] = *subel++;
690 subelt_len = HTON16(val);
691
692 len -= 4; /* for the attr id, attr len fields */
693 len -= subelt_len; /* for the remaining fields in this attribute */
694 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
695 subel, subelt_id, subelt_len));
696
697 if (subelt_id == WPS_ID_VERSION) {
698 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
699 } else if (subelt_id == WPS_ID_REQ_TYPE) {
700 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
701 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
702 valptr[0] = *subel;
703 valptr[1] = *(subel + 1);
704 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
705 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
706 char devname[100];
707 memcpy(devname, subel, subelt_len);
708 devname[subelt_len] = '\0';
709 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
710 devname, subelt_len));
711 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
712 valptr[0] = *subel;
713 valptr[1] = *(subel + 1);
714 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
715 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
716 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
717 valptr[0] = *subel;
718 valptr[1] = *(subel + 1);
719 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
720 valptr[0] = *(subel + 6);
721 valptr[1] = *(subel + 7);
722 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
723 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
724 valptr[0] = *subel;
725 valptr[1] = *(subel + 1);
726 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
727 valptr[0] = *(subel + 6);
728 valptr[1] = *(subel + 7);
729 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
730 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
731 valptr[0] = *subel;
732 valptr[1] = *(subel + 1);
733 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
734 ": cat=%u\n", HTON16(val)));
735 } else {
736 WL_DBG((" unknown attr 0x%x\n", subelt_id));
737 }
738
739 subel += subelt_len;
740 }
741}
742
743static struct net_device* wl_cfg80211_add_monitor_if(char *name)
744{
745 int ret = 0;
746 struct net_device* ndev = NULL;
747
748 ret = dhd_add_monitor(name, &ndev);
749 WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
750 return ndev;
751}
752
753static struct net_device *
754wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
755 enum nl80211_iftype type, u32 *flags,
756 struct vif_params *params)
757{
758 s32 err;
759 s32 timeout = -1;
760 s32 wlif_type = -1;
761 s32 index = 0;
762 s32 mode = 0;
763 chanspec_t chspec;
764 struct wl_priv *wl = wiphy_priv(wiphy);
765 struct net_device *_ndev;
766 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
767 int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
768 bool rollback_lock = false;
769
770 WL_DBG(("if name: %s, type: %d\n", name, type));
771 switch (type) {
772 case NL80211_IFTYPE_ADHOC:
773 case NL80211_IFTYPE_AP_VLAN:
774 case NL80211_IFTYPE_WDS:
775 case NL80211_IFTYPE_MESH_POINT:
776 WL_ERR(("Unsupported interface type\n"));
777 mode = WL_MODE_IBSS;
778 return NULL;
779 case NL80211_IFTYPE_MONITOR:
780 return wl_cfg80211_add_monitor_if(name);
781 case NL80211_IFTYPE_P2P_CLIENT:
782 case NL80211_IFTYPE_STATION:
783 wlif_type = WL_P2P_IF_CLIENT;
784 mode = WL_MODE_BSS;
785 break;
786 case NL80211_IFTYPE_P2P_GO:
787 case NL80211_IFTYPE_AP:
788 wlif_type = WL_P2P_IF_GO;
789 mode = WL_MODE_AP;
790 break;
791 default:
792 WL_ERR(("Unsupported interface type\n"));
793 return NULL;
794 break;
795 }
796
797 if (!name) {
798 WL_ERR(("name is NULL\n"));
799 return NULL;
800 }
801 if (wl->p2p_supported && (wlif_type != -1)) {
802 if (wl_get_p2p_status(wl, IF_DELETING)) {
803 /* wait till IF_DEL is complete
804 * release the lock for the unregister to proceed
805 */
806 if (rtnl_is_locked()) {
807 rtnl_unlock();
808 rollback_lock = true;
809 }
810 WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
811 __func__));
812 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
813 (wl_get_p2p_status(wl, IF_DELETING) == false),
814 msecs_to_jiffies(MAX_WAIT_TIME));
815
816 /* put back the rtnl_lock again */
817 if (rollback_lock) {
818 rtnl_lock();
819 rollback_lock = false;
820 }
821 if (timeout > 0) {
822 WL_ERR(("IF DEL is Success\n"));
823
824 } else {
825 WL_ERR(("timeount < 0, return -EAGAIN\n"));
826 return ERR_PTR(-EAGAIN);
827 }
828 }
829 if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
830 p2p_on(wl) = true;
831 wl_cfgp2p_set_firm_p2p(wl);
832 wl_cfgp2p_init_discovery(wl);
833 }
834 memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
835 strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
836 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
837
838 /* Temporary use channel 11, in case GO will be changed with set_channel API */
839 chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
840
841 /* For P2P mode, use P2P-specific driver features to create the
842 * bss: "wl p2p_ifadd"
843 */
844 wl_set_p2p_status(wl, IF_ADD);
845 err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
846
847 if (unlikely(err))
848 return ERR_PTR(-ENOMEM);
849
850 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
851 (wl_get_p2p_status(wl, IF_ADD) == false),
852 msecs_to_jiffies(MAX_WAIT_TIME));
853 if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
854
855 struct wireless_dev *vwdev;
856 vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
857 if (unlikely(!vwdev)) {
858 WL_ERR(("Could not allocate wireless device\n"));
859 return ERR_PTR(-ENOMEM);
860 }
861 vwdev->wiphy = wl->wdev->wiphy;
862 WL_INFO((" virtual interface(%s) is created memalloc done \n",
863 wl->p2p->vir_ifname));
864 index = alloc_idx_vwdev(wl);
865 wl->vwdev[index] = vwdev;
866 vwdev->iftype =
867 (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
868 : NL80211_IFTYPE_AP;
869 _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
870 _ndev->ieee80211_ptr = vwdev;
871 SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
872 vwdev->netdev = _ndev;
873 wl_set_drv_status(wl, READY);
874 wl->p2p->vif_created = true;
875 set_mode_by_netdev(wl, _ndev, mode);
876 net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
877 if (rtnl_is_locked()) {
878 rtnl_unlock();
879 rollback_lock = true;
880 }
881 if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
882 WL_DBG((" virtual interface(%s) is "
883 "created net attach done\n", wl->p2p->vir_ifname));
884 } else {
885 /* put back the rtnl_lock again */
886 if (rollback_lock)
887 rtnl_lock();
888 goto fail;
889 }
890 /* put back the rtnl_lock again */
891 if (rollback_lock)
892 rtnl_lock();
893 return _ndev;
894
895 } else {
896 wl_clr_p2p_status(wl, IF_ADD);
897 WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname));
898 memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
899 wl->p2p->vif_created = false;
900 }
901 }
902fail:
903 return ERR_PTR(-ENODEV);
904}
905
906static s32
907wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
908{
909 struct ether_addr p2p_mac;
910 struct wl_priv *wl = wiphy_priv(wiphy);
911 s32 timeout = -1;
912 s32 ret = 0;
913 WL_DBG(("Enter\n"));
914 if (wl->p2p_supported) {
915 memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
916 if (wl->p2p->vif_created) {
917 if (wl_get_drv_status(wl, SCANNING)) {
918 wl_cfg80211_scan_abort(wl, dev);
919 }
920 wldev_iovar_setint(dev, "mpc", 1);
921 wl_set_p2p_status(wl, IF_DELETING);
922 ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
923 if (ret) {
924 /* Firmware could not delete the interface so we will not get WLC_E_IF
925 * event for cleaning the dhd virtual nw interace
926 * So lets do it here. Failures from fw will ensure the application to do
927 * ifconfig <inter> down and up sequnce, which will reload the fw
928 * however we should cleanup the linux network virtual interfaces
929 */
930 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
931 WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
932 WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
933 dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
934 }
935
936 /* Wait for any pending scan req to get aborted from the sysioc context */
937 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
938 (wl_get_p2p_status(wl, IF_DELETING) == false),
939 msecs_to_jiffies(MAX_WAIT_TIME));
940 if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
941 WL_DBG(("IFDEL operation done\n"));
942 } else {
943 WL_ERR(("IFDEL didn't complete properly\n"));
944 }
945 ret = dhd_del_monitor(dev);
946 }
947 }
948 return ret;
949}
950
951static s32
952wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
953 enum nl80211_iftype type, u32 *flags,
954 struct vif_params *params)
955{
956 s32 ap = 0;
957 s32 infra = 0;
958 s32 err = BCME_OK;
959 s32 timeout = -1;
960 s32 wlif_type;
961 s32 mode = 0;
962 chanspec_t chspec;
963 struct wl_priv *wl = wiphy_priv(wiphy);
964 WL_DBG(("Enter \n"));
965 switch (type) {
966 case NL80211_IFTYPE_MONITOR:
967 case NL80211_IFTYPE_WDS:
968 case NL80211_IFTYPE_MESH_POINT:
969 ap = 1;
970 WL_ERR(("type (%d) : currently we do not support this type\n",
971 type));
972 break;
973 case NL80211_IFTYPE_ADHOC:
974 mode = WL_MODE_IBSS;
975 break;
976 case NL80211_IFTYPE_STATION:
977 case NL80211_IFTYPE_P2P_CLIENT:
978 mode = WL_MODE_BSS;
979 infra = 1;
980 break;
981 case NL80211_IFTYPE_AP:
982 case NL80211_IFTYPE_AP_VLAN:
983 case NL80211_IFTYPE_P2P_GO:
984 mode = WL_MODE_AP;
985 ap = 1;
986 break;
987 default:
988 return -EINVAL;
989 }
990
991
992 if (ap) {
993 set_mode_by_netdev(wl, ndev, mode);
994 if (wl->p2p_supported && wl->p2p->vif_created) {
995 WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
996 p2p_on(wl)));
997 chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
998 wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
999 WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
1000 ndev->name, ap, infra, type));
1001 wl_set_p2p_status(wl, IF_CHANGING);
1002 wl_clr_p2p_status(wl, IF_CHANGED);
1003 err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
1004 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
1005 (wl_get_p2p_status(wl, IF_CHANGED) == true),
1006 msecs_to_jiffies(MAX_WAIT_TIME));
1007 set_mode_by_netdev(wl, ndev, mode);
1008 wl_clr_p2p_status(wl, IF_CHANGING);
1009 wl_clr_p2p_status(wl, IF_CHANGED);
1010 } else if (ndev == wl_to_prmry_ndev(wl) &&
1011 !wl_get_drv_status(wl, AP_CREATED)) {
1012 wl_set_drv_status(wl, AP_CREATING);
1013 if (!wl->ap_info &&
1014 !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
1015 WL_ERR(("struct ap_saved_ie allocation failed\n"));
1016 return -ENOMEM;
1017 }
1018 } else {
1019 WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
1020 return -EINVAL;
1021 }
1022 }
1023
1024 ndev->ieee80211_ptr->iftype = type;
1025 return 0;
1026}
1027
1028s32
1029wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
1030int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
1031{
1032 struct wl_priv *wl = wlcfg_drv_priv;
1033 s32 ret = BCME_OK;
1034 if (!ndev) {
1035 WL_ERR(("net is NULL\n"));
1036 return 0;
1037 }
1038 if (wl->p2p_supported) {
1039 WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
1040 "new name: %s\n", ndev->name, wl->p2p->vir_ifname));
1041 /* Assign the net device to CONNECT BSSCFG */
1042 strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1);
1043 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = ndev;
1044 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx;
1045 wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach;
1046 ndev->ifindex = idx;
1047 wl_clr_p2p_status(wl, IF_ADD);
1048
1049 wake_up_interruptible(&wl->dongle_event_wait);
1050 }
1051 return ret;
1052}
1053
1054s32
1055wl_cfg80211_notify_ifdel(struct net_device *ndev)
1056{
1057 struct wl_priv *wl = wlcfg_drv_priv;
1058 bool rollback_lock = false;
1059 s32 index = 0;
1060
1061 if (!ndev || !ndev->name) {
1062 WL_ERR(("net is NULL\n"));
1063 return 0;
1064 }
1065
1066 if (p2p_is_on(wl) && wl->p2p->vif_created) {
1067 if (wl->scan_request) {
1068 /* Abort any pending scan requests */
1069 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
1070 if (!rtnl_is_locked()) {
1071 rtnl_lock();
1072 rollback_lock = true;
1073 }
1074 WL_DBG(("ESCAN COMPLETED\n"));
1075 wl_notify_escan_complete(wl, true);
1076 if (rollback_lock)
1077 rtnl_unlock();
1078 }
1079 WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n",
1080 (unsigned int)ndev, wl->p2p->vir_ifname));
1081
1082 memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
1083 index = wl_cfgp2p_find_idx(wl, ndev);
1084 wl_to_p2p_bss_ndev(wl, index) = NULL;
1085 wl_to_p2p_bss_bssidx(wl, index) = 0;
1086 wl->p2p->vif_created = false;
1087 wl_cfgp2p_clear_management_ie(wl,
1088 index);
1089 wl_clr_p2p_status(wl, IF_DELETING);
1090 WL_DBG(("index : %d\n", index));
1091
1092 }
1093 /* Wake up any waiting thread */
1094 wake_up_interruptible(&wl->dongle_event_wait);
1095
1096 return 0;
1097}
1098
1099s32
1100wl_cfg80211_is_progress_ifadd(void)
1101{
1102 s32 is_progress = 0;
1103 struct wl_priv *wl = wlcfg_drv_priv;
1104 if (wl_get_p2p_status(wl, IF_ADD))
1105 is_progress = 1;
1106 return is_progress;
1107}
1108
1109s32
1110wl_cfg80211_is_progress_ifchange(void)
1111{
1112 s32 is_progress = 0;
1113 struct wl_priv *wl = wlcfg_drv_priv;
1114 if (wl_get_p2p_status(wl, IF_CHANGING))
1115 is_progress = 1;
1116 return is_progress;
1117}
1118
1119
1120s32
1121wl_cfg80211_notify_ifchange(void)
1122{
1123 struct wl_priv *wl = wlcfg_drv_priv;
1124 if (wl_get_p2p_status(wl, IF_CHANGING)) {
1125 wl_set_p2p_status(wl, IF_CHANGED);
1126 wake_up_interruptible(&wl->dongle_event_wait);
1127 }
1128 return 0;
1129}
1130
1131static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
1132{
1133 u32 n_ssids = request->n_ssids;
1134 u32 n_channels = request->n_channels;
1135 u16 channel;
1136 chanspec_t chanspec;
1137 s32 i, offset;
1138 char *ptr;
1139 wlc_ssid_t ssid;
1140
1141 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
1142 params->bss_type = DOT11_BSSTYPE_ANY;
1143 params->scan_type = 0;
1144 params->nprobes = -1;
1145 params->active_time = -1;
1146 params->passive_time = -1;
1147 params->home_time = -1;
1148 params->channel_num = 0;
1149 memset(&params->ssid, 0, sizeof(wlc_ssid_t));
1150
1151 WL_SCAN(("Preparing Scan request\n"));
1152 WL_SCAN(("nprobes=%d\n", params->nprobes));
1153 WL_SCAN(("active_time=%d\n", params->active_time));
1154 WL_SCAN(("passive_time=%d\n", params->passive_time));
1155 WL_SCAN(("home_time=%d\n", params->home_time));
1156 WL_SCAN(("scan_type=%d\n", params->scan_type));
1157
1158 params->nprobes = htod32(params->nprobes);
1159 params->active_time = htod32(params->active_time);
1160 params->passive_time = htod32(params->passive_time);
1161 params->home_time = htod32(params->home_time);
1162
1163 /* Copy channel array if applicable */
1164 WL_SCAN(("### List of channelspecs to scan ###\n"));
1165 if (n_channels > 0) {
1166 for (i = 0; i < n_channels; i++) {
1167 chanspec = 0;
1168 channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
1169 if (request->channels[i]->band == IEEE80211_BAND_2GHZ)
1170 chanspec |= WL_CHANSPEC_BAND_2G;
1171 else
1172 chanspec |= WL_CHANSPEC_BAND_5G;
1173
1174 if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40) {
1175 chanspec |= WL_CHANSPEC_BW_20;
1176 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1177 } else {
1178 chanspec |= WL_CHANSPEC_BW_40;
1179 if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40PLUS)
1180 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
1181 else
1182 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
1183 }
1184
1185 params->channel_list[i] = channel;
1186 params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK;
1187 params->channel_list[i] |= chanspec;
1188 WL_SCAN(("Chan : %d, Channel spec: %x \n",
1189 channel, params->channel_list[i]));
1190 params->channel_list[i] = htod16(params->channel_list[i]);
1191 }
1192 } else {
1193 WL_SCAN(("Scanning all channels\n"));
1194 }
1195
1196 /* Copy ssid array if applicable */
1197 WL_SCAN(("### List of SSIDs to scan ###\n"));
1198 if (n_ssids > 0) {
1199 offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
1200 offset = roundup(offset, sizeof(u32));
1201 ptr = (char*)params + offset;
1202 for (i = 0; i < n_ssids; i++) {
1203 memset(&ssid, 0, sizeof(wlc_ssid_t));
1204 ssid.SSID_len = request->ssids[i].ssid_len;
1205 memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
1206 if (!ssid.SSID_len)
1207 WL_SCAN(("%d: Broadcast scan\n", i));
1208 else
1209 WL_SCAN(("%d: scan for %s size =%d\n", i,
1210 ssid.SSID, ssid.SSID_len));
1211 memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
1212 ptr += sizeof(wlc_ssid_t);
1213 }
1214 } else {
1215 WL_SCAN(("Broadcast scan\n"));
1216 }
1217 /* Adding mask to channel numbers */
1218 params->channel_num =
1219 htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
1220 (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
1221}
1222
1223static s32
1224wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action)
1225{
1226 u32 n_channels;
1227 u32 n_ssids;
1228 s32 params_size =
1229 (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
1230 struct wl_iscan_params *params;
1231 s32 err = 0;
1232
1233 if (request != NULL) {
1234 n_channels = request->n_channels;
1235 n_ssids = request->n_ssids;
1236 /* Allocate space for populating ssids in wl_iscan_params struct */
1237 if (n_channels % 2)
1238 /* If n_channels is odd, add a padd of u16 */
1239 params_size += sizeof(u16) * (n_channels + 1);
1240 else
1241 params_size += sizeof(u16) * n_channels;
1242
1243 /* Allocate space for populating ssids in wl_iscan_params struct */
1244 params_size += sizeof(struct wlc_ssid) * n_ssids;
1245 }
1246 params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
1247 if (!params) {
1248 return -ENOMEM;
1249 }
1250
1251 if (request != NULL)
1252 wl_scan_prep(&params->params, request);
1253
1254 params->version = htod32(ISCAN_REQ_VERSION);
1255 params->action = htod16(action);
1256 params->scan_duration = htod16(0);
1257
1258 if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) {
1259 WL_ERR(("ioctl buffer length is not sufficient\n"));
1260 err = -ENOMEM;
1261 goto done;
1262 }
1263 err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
1264 iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
1265 if (unlikely(err)) {
1266 if (err == -EBUSY) {
1267 WL_ERR(("system busy : iscan canceled\n"));
1268 } else {
1269 WL_ERR(("error (%d)\n", err));
1270 }
1271 }
1272done:
1273 kfree(params);
1274 return err;
1275}
1276
1277static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request)
1278{
1279 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
1280 struct net_device *ndev = wl_to_prmry_ndev(wl);
1281 s32 passive_scan;
1282 s32 err = 0;
1283
1284 iscan->state = WL_ISCAN_STATE_SCANING;
1285
1286 passive_scan = wl->active_scan ? 0 : 1;
1287 err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
1288 &passive_scan, sizeof(passive_scan), false);
1289 if (unlikely(err)) {
1290 WL_DBG(("error (%d)\n", err));
1291 return err;
1292 }
1293 wl->iscan_kickstart = true;
1294 wl_run_iscan(iscan, request, WL_SCAN_ACTION_START);
1295 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
1296 iscan->timer_on = 1;
1297
1298 return err;
1299}
1300
1301static s32
1302wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
1303 struct cfg80211_scan_request *request, uint16 action)
1304{
1305 s32 err = BCME_OK;
1306 u32 n_channels;
1307 u32 n_ssids;
1308 s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
1309 wl_escan_params_t *params;
1310 struct cfg80211_scan_request *scan_request = wl->scan_request;
1311 u32 num_chans = 0;
1312 s32 search_state = WL_P2P_DISC_ST_SCAN;
1313 u32 i;
1314 u16 *default_chan_list = NULL;
1315 struct net_device *dev = NULL;
1316 WL_DBG(("Enter \n"));
1317
1318
1319 if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) &&
1320 !p2p_scan(wl))) {
1321 /* LEGACY SCAN TRIGGER */
1322 WL_SCAN((" LEGACY E-SCAN START\n"));
1323
1324 if (request != NULL) {
1325 n_channels = request->n_channels;
1326 n_ssids = request->n_ssids;
1327 /* Allocate space for populating ssids in wl_iscan_params struct */
1328 if (n_channels % 2)
1329 /* If n_channels is odd, add a padd of u16 */
1330 params_size += sizeof(u16) * (n_channels + 1);
1331 else
1332 params_size += sizeof(u16) * n_channels;
1333
1334 /* Allocate space for populating ssids in wl_iscan_params struct */
1335 params_size += sizeof(struct wlc_ssid) * n_ssids;
1336 }
1337 params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
1338 if (params == NULL) {
1339 err = -ENOMEM;
1340 goto exit;
1341 }
1342
1343 if (request != NULL)
1344 wl_scan_prep(&params->params, request);
1345 params->version = htod32(ESCAN_REQ_VERSION);
1346 params->action = htod16(action);
1347 params->sync_id = htod16(0x1234);
1348 if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
1349 WL_ERR(("ioctl buffer length not sufficient\n"));
1350 kfree(params);
1351 err = -ENOMEM;
1352 goto exit;
1353 }
1354 err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
1355 wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
1356 if (unlikely(err))
1357 WL_ERR((" Escan set error (%d)\n", err));
1358 kfree(params);
1359 }
1360 else if (p2p_on(wl) && p2p_scan(wl)) {
1361 /* P2P SCAN TRIGGER */
1362 if (scan_request && scan_request->n_channels) {
1363 num_chans = scan_request->n_channels;
1364 WL_SCAN((" chann number : %d\n", num_chans));
1365 default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
1366 GFP_KERNEL);
1367 if (default_chan_list == NULL) {
1368 WL_ERR(("channel list allocation failed \n"));
1369 err = -ENOMEM;
1370 goto exit;
1371 }
1372 for (i = 0; i < num_chans; i++)
1373 {
1374 default_chan_list[i] =
1375 ieee80211_frequency_to_channel(
1376 scan_request->channels[i]->center_freq);
1377 }
1378 if (num_chans == 3 && (
1379 (default_chan_list[0] == SOCIAL_CHAN_1) &&
1380 (default_chan_list[1] == SOCIAL_CHAN_2) &&
1381 (default_chan_list[2] == SOCIAL_CHAN_3))) {
1382 /* SOCIAL CHANNELS 1, 6, 11 */
1383 search_state = WL_P2P_DISC_ST_SEARCH;
1384 WL_INFO(("P2P SEARCH PHASE START \n"));
1385 } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) &&
1386 (get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
1387 /* If you are already a GO, then do SEARCH only */
1388 WL_INFO(("Already a GO. Do SEARCH Only"));
1389 search_state = WL_P2P_DISC_ST_SEARCH;
1390 } else {
1391 WL_INFO(("P2P SCAN STATE START \n"));
1392 }
1393
1394 }
1395 err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list,
1396 search_state, action,
1397 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1398 kfree(default_chan_list);
1399 }
1400exit:
1401 if (unlikely(err)) {
1402 WL_ERR(("error (%d)\n", err));
1403 }
1404 return err;
1405}
1406
1407
1408static s32
1409wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev,
1410 struct cfg80211_scan_request *request)
1411{
1412 s32 err = BCME_OK;
1413 s32 passive_scan;
1414 wl_scan_results_t *results;
1415 WL_SCAN(("Enter \n"));
1416
1417 wl->escan_info.wiphy = wiphy;
1418 wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
1419 passive_scan = wl->active_scan ? 0 : 1;
1420 err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
1421 &passive_scan, sizeof(passive_scan), false);
1422 if (unlikely(err)) {
1423 WL_ERR(("error (%d)\n", err));
1424 return err;
1425 }
1426 results = (wl_scan_results_t *) wl->escan_info.escan_buf;
1427 results->version = 0;
1428 results->count = 0;
1429 results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
1430
1431 err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START);
1432 return err;
1433}
1434
1435static s32
1436__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
1437 struct cfg80211_scan_request *request,
1438 struct cfg80211_ssid *this_ssid)
1439{
1440 struct wl_priv *wl = wiphy_priv(wiphy);
1441 struct cfg80211_ssid *ssids;
1442 struct wl_scan_req *sr = wl_to_sr(wl);
1443 wpa_ie_fixed_t *wps_ie;
1444 s32 passive_scan;
1445 bool iscan_req;
1446 bool escan_req;
1447 bool spec_scan;
1448 bool p2p_ssid;
1449 s32 err = 0;
1450 s32 i;
1451 u32 wpsie_len = 0;
1452 u8 wpsie[IE_MAX_LEN];
1453
1454 WL_DBG(("Enter wiphy (%p)\n", wiphy));
1455 if (unlikely(wl_get_drv_status(wl, SCANNING))) {
1456 WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
1457 return -EAGAIN;
1458 }
1459 if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) {
1460 WL_ERR(("Scanning being aborted : status (%d)\n",
1461 (int)wl->status));
1462 return -EAGAIN;
1463 }
1464 if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
1465 WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
1466 return -EOPNOTSUPP;
1467 }
1468
1469 /* Arm scan timeout timer */
1470 mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
1471 iscan_req = false;
1472 spec_scan = false;
1473 if (request) { /* scan bss */
1474 ssids = request->ssids;
1475 if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
1476 iscan_req = true;
1477 } else if (wl->escan_on) {
1478 escan_req = true;
1479 p2p_ssid = false;
1480 for (i = 0; i < request->n_ssids; i++) {
1481 if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid)) {
1482 p2p_ssid = true;
1483 break;
1484 }
1485 }
1486 if (p2p_ssid) {
1487 if (wl->p2p_supported) {
1488 /* p2p scan trigger */
1489 if (p2p_on(wl) == false) {
1490 /* p2p on at the first time */
1491 p2p_on(wl) = true;
1492 wl_cfgp2p_set_firm_p2p(wl);
1493 }
1494 p2p_scan(wl) = true;
1495 }
1496 } else {
1497 /* legacy scan trigger
1498 * So, we have to disable p2p discovery if p2p discovery is on
1499 */
1500 if (wl->p2p_supported) {
1501 p2p_scan(wl) = false;
1502 /* If Netdevice is not equals to primary and p2p is on
1503 * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
1504 */
1505 if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl)))
1506 p2p_scan(wl) = true;
1507
1508 if (p2p_scan(wl) == false) {
1509 if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
1510 err = wl_cfgp2p_discover_enable_search(wl,
1511 false);
1512 if (unlikely(err)) {
1513 goto scan_out;
1514 }
1515
1516 }
1517 }
1518 }
1519 if (!wl->p2p_supported || !p2p_scan(wl)) {
1520 if (ndev == wl_to_prmry_ndev(wl)) {
1521 /* find the WPSIE */
1522 memset(wpsie, 0, sizeof(wpsie));
1523 if ((wps_ie = wl_cfgp2p_find_wpsie(
1524 (u8 *)request->ie,
1525 request->ie_len)) != NULL) {
1526 wpsie_len =
1527 wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
1528 memcpy(wpsie, wps_ie, wpsie_len);
1529 } else {
1530 wpsie_len = 0;
1531 }
1532 err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
1533 VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
1534 if (unlikely(err)) {
1535 goto scan_out;
1536 }
1537 }
1538 }
1539 }
1540 }
1541 } else { /* scan in ibss */
1542 /* we don't do iscan in ibss */
1543 ssids = this_ssid;
1544 }
1545 wl->scan_request = request;
1546 wl_set_drv_status(wl, SCANNING);
1547 if (iscan_req) {
1548 err = wl_do_iscan(wl, request);
1549 if (likely(!err))
1550 return err;
1551 else
1552 goto scan_out;
1553 } else if (escan_req) {
1554 if (wl->p2p_supported) {
1555 if (p2p_on(wl) && p2p_scan(wl)) {
1556
1557 err = wl_cfgp2p_enable_discovery(wl, ndev,
1558 request->ie, request->ie_len);
1559
1560 if (unlikely(err)) {
1561 goto scan_out;
1562 }
1563 }
1564 }
1565 err = wl_do_escan(wl, wiphy, ndev, request);
1566 if (likely(!err))
1567 return err;
1568 else
1569 goto scan_out;
1570
1571
1572 } else {
1573 memset(&sr->ssid, 0, sizeof(sr->ssid));
1574 sr->ssid.SSID_len =
1575 min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
1576 if (sr->ssid.SSID_len) {
1577 memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
1578 sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
1579 WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n",
1580 sr->ssid.SSID, sr->ssid.SSID_len));
1581 spec_scan = true;
1582 } else {
1583 WL_SCAN(("Broadcast scan\n"));
1584 }
1585 WL_SCAN(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
1586 passive_scan = wl->active_scan ? 0 : 1;
1587 err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
1588 &passive_scan, sizeof(passive_scan), false);
1589 if (unlikely(err)) {
1590 WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
1591 goto scan_out;
1592 }
1593 err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid,
1594 sizeof(sr->ssid), false);
1595 if (err) {
1596 if (err == -EBUSY) {
1597 WL_ERR(("system busy : scan for \"%s\" "
1598 "canceled\n", sr->ssid.SSID));
1599 } else {
1600 WL_ERR(("WLC_SCAN error (%d)\n", err));
1601 }
1602 goto scan_out;
1603 }
1604 }
1605
1606 return 0;
1607
1608scan_out:
1609 wl_clr_drv_status(wl, SCANNING);
1610 wl->scan_request = NULL;
1611 return err;
1612}
1613
1614static s32
1615wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
1616 struct cfg80211_scan_request *request)
1617{
1618 s32 err = 0;
1619 struct wl_priv *wl = wiphy_priv(wiphy);
1620
1621 WL_DBG(("Enter \n"));
1622 CHECK_SYS_UP(wl);
1623
1624 err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
1625 if (unlikely(err)) {
1626 WL_ERR(("scan error (%d)\n", err));
1627 return err;
1628 }
1629
1630 return err;
1631}
1632
1633static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
1634{
1635 s8 buf[WLC_IOCTL_SMLEN];
1636 u32 len;
1637 s32 err = 0;
1638
1639 val = htod32(val);
1640 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
1641 BUG_ON(unlikely(!len));
1642
1643 err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
1644 if (unlikely(err)) {
1645 WL_ERR(("error (%d)\n", err));
1646 }
1647
1648 return err;
1649}
1650
1651static s32
1652wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
1653{
1654 union {
1655 s8 buf[WLC_IOCTL_SMLEN];
1656 s32 val;
1657 } var;
1658 u32 len;
1659 u32 data_null;
1660 s32 err = 0;
1661
1662 len = bcm_mkiovar(name, (char *)(&data_null), 0,
1663 (char *)(&var), sizeof(var.buf));
1664 BUG_ON(unlikely(!len));
1665 err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
1666 if (unlikely(err)) {
1667 WL_ERR(("error (%d)\n", err));
1668 }
1669 *retval = dtoh32(var.val);
1670
1671 return err;
1672}
1673
1674static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
1675{
1676 s32 err = 0;
1677
1678 err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
1679 if (unlikely(err)) {
1680 WL_ERR(("Error (%d)\n", err));
1681 return err;
1682 }
1683 return err;
1684}
1685
1686static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
1687{
1688 s32 err = 0;
1689
1690 err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
1691 if (unlikely(err)) {
1692 WL_ERR(("Error (%d)\n", err));
1693 return err;
1694 }
1695 return err;
1696}
1697
1698static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
1699{
1700 s32 err = 0;
1701 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
1702
1703 retry = htod32(retry);
1704 err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), false);
1705 if (unlikely(err)) {
1706 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
1707 return err;
1708 }
1709 return err;
1710}
1711
1712static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1713{
1714 struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy);
1715 struct net_device *ndev = wl_to_prmry_ndev(wl);
1716 s32 err = 0;
1717
1718 CHECK_SYS_UP(wl);
1719 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
1720 (wl->conf->rts_threshold != wiphy->rts_threshold)) {
1721 wl->conf->rts_threshold = wiphy->rts_threshold;
1722 err = wl_set_rts(ndev, wl->conf->rts_threshold);
1723 if (!err)
1724 return err;
1725 }
1726 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
1727 (wl->conf->frag_threshold != wiphy->frag_threshold)) {
1728 wl->conf->frag_threshold = wiphy->frag_threshold;
1729 err = wl_set_frag(ndev, wl->conf->frag_threshold);
1730 if (!err)
1731 return err;
1732 }
1733 if (changed & WIPHY_PARAM_RETRY_LONG &&
1734 (wl->conf->retry_long != wiphy->retry_long)) {
1735 wl->conf->retry_long = wiphy->retry_long;
1736 err = wl_set_retry(ndev, wl->conf->retry_long, true);
1737 if (!err)
1738 return err;
1739 }
1740 if (changed & WIPHY_PARAM_RETRY_SHORT &&
1741 (wl->conf->retry_short != wiphy->retry_short)) {
1742 wl->conf->retry_short = wiphy->retry_short;
1743 err = wl_set_retry(ndev, wl->conf->retry_short, false);
1744 if (!err) {
1745 return err;
1746 }
1747 }
1748
1749 return err;
1750}
1751
1752static s32
1753wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1754 struct cfg80211_ibss_params *params)
1755{
1756 struct wl_priv *wl = wiphy_priv(wiphy);
1757 struct cfg80211_bss *bss;
1758 struct ieee80211_channel *chan;
1759 struct wl_join_params join_params;
1760 struct cfg80211_ssid ssid;
1761 s32 scan_retry = 0;
1762 s32 err = 0;
1763 bool rollback_lock = false;
1764
1765 WL_TRACE(("In\n"));
1766 CHECK_SYS_UP(wl);
1767 if (params->bssid) {
1768 WL_ERR(("Invalid bssid\n"));
1769 return -EOPNOTSUPP;
1770 }
1771 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
1772 if (!bss) {
1773 memcpy(ssid.ssid, params->ssid, params->ssid_len);
1774 ssid.ssid_len = params->ssid_len;
1775 do {
1776 if (unlikely
1777 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
1778 -EBUSY)) {
1779 wl_delay(150);
1780 } else {
1781 break;
1782 }
1783 } while (++scan_retry < WL_SCAN_RETRY_MAX);
1784 /* to allow scan_inform to propagate to cfg80211 plane */
1785 if (rtnl_is_locked()) {
1786 rtnl_unlock();
1787 rollback_lock = true;
1788 }
1789
1790 /* wait 4 secons till scan done.... */
1791 schedule_timeout_interruptible(4 * HZ);
1792 if (rollback_lock)
1793 rtnl_lock();
1794 bss = cfg80211_get_ibss(wiphy, NULL,
1795 params->ssid, params->ssid_len);
1796 }
1797 if (bss) {
1798 wl->ibss_starter = false;
1799 WL_DBG(("Found IBSS\n"));
1800 } else {
1801 wl->ibss_starter = true;
1802 }
1803 chan = params->channel;
1804 if (chan)
1805 wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
1806 /*
1807 * Join with specific BSSID and cached SSID
1808 * If SSID is zero join based on BSSID only
1809 */
1810 memset(&join_params, 0, sizeof(join_params));
1811 memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
1812 params->ssid_len);
1813 join_params.ssid.SSID_len = htod32(params->ssid_len);
1814 if (params->bssid)
1815 memcpy(&join_params.params.bssid, params->bssid,
1816 ETHER_ADDR_LEN);
1817 else
1818 memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
1819
1820 err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
1821 sizeof(join_params), false);
1822 if (unlikely(err)) {
1823 WL_ERR(("Error (%d)\n", err));
1824 return err;
1825 }
1826 return err;
1827}
1828
1829static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
1830{
1831 struct wl_priv *wl = wiphy_priv(wiphy);
1832 s32 err = 0;
1833
1834 CHECK_SYS_UP(wl);
1835 wl_link_down(wl);
1836
1837 return err;
1838}
1839
1840static s32
1841wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
1842{
1843 struct wl_priv *wl = wlcfg_drv_priv;
1844 struct wl_security *sec;
1845 s32 val = 0;
1846 s32 err = 0;
1847 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1848
1849 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1850 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1851 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1852 val = WPA2_AUTH_PSK| WPA2_AUTH_UNSPECIFIED;
1853 else
1854 val = WPA_AUTH_DISABLED;
1855
1856 if (is_wps_conn(sme))
1857 val = WPA_AUTH_DISABLED;
1858
1859 WL_DBG(("setting wpa_auth to 0x%0x\n", val));
1860 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
1861 if (unlikely(err)) {
1862 WL_ERR(("set wpa_auth failed (%d)\n", err));
1863 return err;
1864 }
1865 sec = wl_read_prof(wl, WL_PROF_SEC);
1866 sec->wpa_versions = sme->crypto.wpa_versions;
1867 return err;
1868}
1869
1870static s32
1871wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
1872{
1873 struct wl_priv *wl = wlcfg_drv_priv;
1874 struct wl_security *sec;
1875 s32 val = 0;
1876 s32 err = 0;
1877 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1878 switch (sme->auth_type) {
1879 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1880 val = 0;
1881 WL_DBG(("open system\n"));
1882 break;
1883 case NL80211_AUTHTYPE_SHARED_KEY:
1884 val = 1;
1885 WL_DBG(("shared key\n"));
1886 break;
1887 case NL80211_AUTHTYPE_AUTOMATIC:
1888 val = 2;
1889 WL_DBG(("automatic\n"));
1890 break;
1891 case NL80211_AUTHTYPE_NETWORK_EAP:
1892 WL_DBG(("network eap\n"));
1893 default:
1894 val = 2;
1895 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
1896 break;
1897 }
1898
1899 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
1900 if (unlikely(err)) {
1901 WL_ERR(("set auth failed (%d)\n", err));
1902 return err;
1903 }
1904 sec = wl_read_prof(wl, WL_PROF_SEC);
1905 sec->auth_type = sme->auth_type;
1906 return err;
1907}
1908
1909static s32
1910wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
1911{
1912 struct wl_priv *wl = wlcfg_drv_priv;
1913 struct wl_security *sec;
1914 s32 pval = 0;
1915 s32 gval = 0;
1916 s32 err = 0;
1917 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1918
1919 if (sme->crypto.n_ciphers_pairwise) {
1920 switch (sme->crypto.ciphers_pairwise[0]) {
1921 case WLAN_CIPHER_SUITE_WEP40:
1922 case WLAN_CIPHER_SUITE_WEP104:
1923 pval = WEP_ENABLED;
1924 break;
1925 case WLAN_CIPHER_SUITE_TKIP:
1926 pval = TKIP_ENABLED;
1927 break;
1928 case WLAN_CIPHER_SUITE_CCMP:
1929 pval = AES_ENABLED;
1930 break;
1931 case WLAN_CIPHER_SUITE_AES_CMAC:
1932 pval = AES_ENABLED;
1933 break;
1934 default:
1935 WL_ERR(("invalid cipher pairwise (%d)\n",
1936 sme->crypto.ciphers_pairwise[0]));
1937 return -EINVAL;
1938 }
1939 }
1940 if (sme->crypto.cipher_group) {
1941 switch (sme->crypto.cipher_group) {
1942 case WLAN_CIPHER_SUITE_WEP40:
1943 case WLAN_CIPHER_SUITE_WEP104:
1944 gval = WEP_ENABLED;
1945 break;
1946 case WLAN_CIPHER_SUITE_TKIP:
1947 gval = TKIP_ENABLED;
1948 break;
1949 case WLAN_CIPHER_SUITE_CCMP:
1950 gval = AES_ENABLED;
1951 break;
1952 case WLAN_CIPHER_SUITE_AES_CMAC:
1953 gval = AES_ENABLED;
1954 break;
1955 default:
1956 WL_ERR(("invalid cipher group (%d)\n",
1957 sme->crypto.cipher_group));
1958 return -EINVAL;
1959 }
1960 }
1961
1962 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
1963
1964 if (is_wps_conn(sme)) {
1965 err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
1966 } else {
1967 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
1968 err = wldev_iovar_setint_bsscfg(dev, "wsec",
1969 pval | gval, bssidx);
1970 }
1971 if (unlikely(err)) {
1972 WL_ERR(("error (%d)\n", err));
1973 return err;
1974 }
1975
1976 sec = wl_read_prof(wl, WL_PROF_SEC);
1977 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1978 sec->cipher_group = sme->crypto.cipher_group;
1979
1980 return err;
1981}
1982
1983static s32
1984wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
1985{
1986 struct wl_priv *wl = wlcfg_drv_priv;
1987 struct wl_security *sec;
1988 s32 val = 0;
1989 s32 err = 0;
1990 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1991
1992 if (sme->crypto.n_akm_suites) {
1993 err = wl_dev_intvar_get(dev, "wpa_auth", &val);
1994 if (unlikely(err)) {
1995 WL_ERR(("could not get wpa_auth (%d)\n", err));
1996 return err;
1997 }
1998 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1999 switch (sme->crypto.akm_suites[0]) {
2000 case WLAN_AKM_SUITE_8021X:
2001 val = WPA_AUTH_UNSPECIFIED;
2002 break;
2003 case WLAN_AKM_SUITE_PSK:
2004 val = WPA_AUTH_PSK;
2005 break;
2006 default:
2007 WL_ERR(("invalid cipher group (%d)\n",
2008 sme->crypto.cipher_group));
2009 return -EINVAL;
2010 }
2011 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
2012 switch (sme->crypto.akm_suites[0]) {
2013 case WLAN_AKM_SUITE_8021X:
2014 val = WPA2_AUTH_UNSPECIFIED;
2015 break;
2016 case WLAN_AKM_SUITE_PSK:
2017 val = WPA2_AUTH_PSK;
2018 break;
2019 default:
2020 WL_ERR(("invalid cipher group (%d)\n",
2021 sme->crypto.cipher_group));
2022 return -EINVAL;
2023 }
2024 }
2025 WL_DBG(("setting wpa_auth to %d\n", val));
2026
2027 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
2028 if (unlikely(err)) {
2029 WL_ERR(("could not set wpa_auth (%d)\n", err));
2030 return err;
2031 }
2032 }
2033 sec = wl_read_prof(wl, WL_PROF_SEC);
2034 sec->wpa_auth = sme->crypto.akm_suites[0];
2035
2036 return err;
2037}
2038
2039static s32
2040wl_set_set_sharedkey(struct net_device *dev,
2041 struct cfg80211_connect_params *sme)
2042{
2043 struct wl_priv *wl = wlcfg_drv_priv;
2044 struct wl_security *sec;
2045 struct wl_wsec_key key;
2046 s32 val;
2047 s32 err = 0;
2048 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2049
2050 WL_DBG(("key len (%d)\n", sme->key_len));
2051 if (sme->key_len) {
2052 sec = wl_read_prof(wl, WL_PROF_SEC);
2053 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
2054 sec->wpa_versions, sec->cipher_pairwise));
2055 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
2056 NL80211_WPA_VERSION_2)) &&
2057 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
2058 WLAN_CIPHER_SUITE_WEP104))) {
2059 memset(&key, 0, sizeof(key));
2060 key.len = (u32) sme->key_len;
2061 key.index = (u32) sme->key_idx;
2062 if (unlikely(key.len > sizeof(key.data))) {
2063 WL_ERR(("Too long key length (%u)\n", key.len));
2064 return -EINVAL;
2065 }
2066 memcpy(key.data, sme->key, key.len);
2067 key.flags = WL_PRIMARY_KEY;
2068 switch (sec->cipher_pairwise) {
2069 case WLAN_CIPHER_SUITE_WEP40:
2070 key.algo = CRYPTO_ALGO_WEP1;
2071 break;
2072 case WLAN_CIPHER_SUITE_WEP104:
2073 key.algo = CRYPTO_ALGO_WEP128;
2074 break;
2075 default:
2076 WL_ERR(("Invalid algorithm (%d)\n",
2077 sme->crypto.ciphers_pairwise[0]));
2078 return -EINVAL;
2079 }
2080 /* Set the new key/index */
2081 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
2082 key.len, key.index, key.algo));
2083 WL_DBG(("key \"%s\"\n", key.data));
2084 swap_key_from_BE(&key);
2085 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
2086 ioctlbuf, sizeof(ioctlbuf), bssidx);
2087 if (unlikely(err)) {
2088 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2089 return err;
2090 }
2091 if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
2092 WL_DBG(("set auth_type to shared key\n"));
2093 val = 1; /* shared key */
2094 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
2095 if (unlikely(err)) {
2096 WL_ERR(("set auth failed (%d)\n", err));
2097 return err;
2098 }
2099 }
2100 }
2101 }
2102 return err;
2103}
2104
2105static s32
2106wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
2107 struct cfg80211_connect_params *sme)
2108{
2109 struct wl_priv *wl = wiphy_priv(wiphy);
2110 struct ieee80211_channel *chan = sme->channel;
2111 wl_extjoin_params_t *ext_join_params;
2112 struct wl_join_params join_params;
2113 size_t join_params_size;
2114 s32 err = 0;
2115 wpa_ie_fixed_t *wpa_ie;
2116 wpa_ie_fixed_t *wps_ie;
2117 bcm_tlv_t *wpa2_ie;
2118 u8* wpaie = 0;
2119 u32 wpaie_len = 0;
2120 u32 wpsie_len = 0;
2121 u32 chan_cnt = 0;
2122 u8 wpsie[IE_MAX_LEN];
2123 struct ether_addr bssid;
2124
2125 WL_DBG(("In\n"));
2126 CHECK_SYS_UP(wl);
2127
2128 /*
2129 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
2130 */
2131 if (wl->scan_request) {
2132 wl_cfg80211_scan_abort(wl, dev);
2133 }
2134 /* Clean BSSID */
2135 bzero(&bssid, sizeof(bssid));
2136 wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID);
2137
2138 if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
2139 /* we only allow to connect using virtual interface in case of P2P */
2140 if (p2p_on(wl) && is_wps_conn(sme)) {
2141 WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n",
2142 wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
2143 /* Have to apply WPS IE + P2P IE in assoc req frame */
2144 wl_cfgp2p_set_management_ie(wl, dev,
2145 wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG,
2146 wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie,
2147 wl_to_p2p_bss_saved_ie(wl,
2148 P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len);
2149 wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
2150 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
2151 } else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
2152 /* This is the connect req after WPS is done [credentials exchanged]
2153 * currently identified with WPA_VERSION_2 .
2154 * Update the previously set IEs with
2155 * the newly received IEs from Supplicant. This will remove the WPS IE from
2156 * the Assoc Req.
2157 */
2158 WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n",
2159 wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
2160 wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
2161 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
2162 }
2163
2164 } else if (dev == wl_to_prmry_ndev(wl)) {
2165 /* find the RSN_IE */
2166 if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
2167 DOT11_MNG_RSN_ID)) != NULL) {
2168 WL_DBG((" WPA2 IE is found\n"));
2169 }
2170 /* find the WPA_IE */
2171 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie,
2172 sme->ie_len)) != NULL) {
2173 WL_DBG((" WPA IE is found\n"));
2174 }
2175 if (wpa_ie != NULL || wpa2_ie != NULL) {
2176 wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
2177 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
2178 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
2179 wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
2180 ioctlbuf, sizeof(ioctlbuf));
2181 } else {
2182 wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
2183 ioctlbuf, sizeof(ioctlbuf));
2184 }
2185
2186 /* find the WPSIE */
2187 memset(wpsie, 0, sizeof(wpsie));
2188 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)sme->ie,
2189 sme->ie_len)) != NULL) {
2190 wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
2191 memcpy(wpsie, wps_ie, wpsie_len);
2192 } else {
2193 wpsie_len = 0;
2194 }
2195 err = wl_cfgp2p_set_management_ie(wl, dev, -1,
2196 VNDR_IE_ASSOCREQ_FLAG, wpsie, wpsie_len);
2197 if (unlikely(err)) {
2198 return err;
2199 }
2200 }
2201 if (unlikely(!sme->ssid)) {
2202 WL_ERR(("Invalid ssid\n"));
2203 return -EOPNOTSUPP;
2204 }
2205 if (chan) {
2206 wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
2207 chan_cnt = 1;
2208 WL_DBG(("channel (%d), center_req (%d)\n", wl->channel,
2209 chan->center_freq));
2210 } else
2211 wl->channel = 0;
2212 WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len));
2213 err = wl_set_wpa_version(dev, sme);
2214 if (unlikely(err)) {
2215 WL_ERR(("Invalid wpa_version\n"));
2216 return err;
2217 }
2218
2219 err = wl_set_auth_type(dev, sme);
2220 if (unlikely(err)) {
2221 WL_ERR(("Invalid auth type\n"));
2222 return err;
2223 }
2224
2225 err = wl_set_set_cipher(dev, sme);
2226 if (unlikely(err)) {
2227 WL_ERR(("Invalid ciper\n"));
2228 return err;
2229 }
2230
2231 err = wl_set_key_mgmt(dev, sme);
2232 if (unlikely(err)) {
2233 WL_ERR(("Invalid key mgmt\n"));
2234 return err;
2235 }
2236
2237 err = wl_set_set_sharedkey(dev, sme);
2238 if (unlikely(err)) {
2239 WL_ERR(("Invalid shared key\n"));
2240 return err;
2241 }
2242
2243 /*
2244 * Join with specific BSSID and cached SSID
2245 * If SSID is zero join based on BSSID only
2246 */
2247 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
2248 chan_cnt * sizeof(chanspec_t);
2249 ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
2250 if (ext_join_params == NULL) {
2251 err = -ENOMEM;
2252 wl_clr_drv_status(wl, CONNECTING);
2253 goto exit;
2254 }
2255 ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
2256 memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
2257 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
2258 /* Set up join scan parameters */
2259 ext_join_params->scan.scan_type = -1;
2260 ext_join_params->scan.nprobes = 2;
2261 /* increate dwell time to receive probe response
2262 * from target AP at a noisy air
2263 */
2264 ext_join_params->scan.active_time = 150;
2265 ext_join_params->scan.passive_time = 300;
2266 ext_join_params->scan.home_time = -1;
2267 if (sme->bssid)
2268 memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
2269 else
2270 memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
2271 ext_join_params->assoc.chanspec_num = chan_cnt;
2272 if (chan_cnt) {
2273 u16 channel, band, bw, ctl_sb;
2274 chanspec_t chspec;
2275 channel = wl->channel;
2276 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
2277 : WL_CHANSPEC_BAND_5G;
2278 bw = WL_CHANSPEC_BW_20;
2279 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
2280 chspec = (channel | band | bw | ctl_sb);
2281 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
2282 ext_join_params->assoc.chanspec_list[0] |= chspec;
2283 ext_join_params->assoc.chanspec_list[0] =
2284 htodchanspec(ext_join_params->assoc.chanspec_list[0]);
2285 }
2286 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
2287 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
2288 WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
2289 ext_join_params->ssid.SSID_len));
2290 }
2291 wl_set_drv_status(wl, CONNECTING);
2292 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
2293 sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
2294 kfree(ext_join_params);
2295 if (err) {
2296 wl_clr_drv_status(wl, CONNECTING);
2297 if (err == BCME_UNSUPPORTED) {
2298 WL_DBG(("join iovar is not supported\n"));
2299 goto set_ssid;
2300 } else
2301 WL_ERR(("error (%d)\n", err));
2302 } else
2303 goto exit;
2304
2305set_ssid:
2306 memset(&join_params, 0, sizeof(join_params));
2307 join_params_size = sizeof(join_params.ssid);
2308
2309 join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
2310 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
2311 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
2312 wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
2313 if (sme->bssid)
2314 memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
2315 else
2316 memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
2317
2318 wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
2319 WL_DBG(("join_param_size %d\n", join_params_size));
2320
2321 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
2322 WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
2323 join_params.ssid.SSID_len));
2324 }
2325 wl_set_drv_status(wl, CONNECTING);
2326 err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
2327 if (err) {
2328 WL_ERR(("error (%d)\n", err));
2329 wl_clr_drv_status(wl, CONNECTING);
2330 }
2331exit:
2332 return err;
2333}
2334
2335static s32
2336wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
2337 u16 reason_code)
2338{
2339 struct wl_priv *wl = wiphy_priv(wiphy);
2340 scb_val_t scbval;
2341 bool act = false;
2342 s32 err = 0;
2343 u8 *curbssid;
2344 WL_ERR(("Reason %d\n", reason_code));
2345 CHECK_SYS_UP(wl);
2346 act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
2347 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
2348 if (likely(act)) {
2349 /*
2350 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
2351 */
2352 if (wl->scan_request) {
2353 wl_cfg80211_scan_abort(wl, dev);
2354 }
2355 wl_set_drv_status(wl, DISCONNECTING);
2356 scbval.val = reason_code;
2357 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
2358 scbval.val = htod32(scbval.val);
2359 err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
2360 sizeof(scb_val_t), true);
2361 if (unlikely(err)) {
2362 wl_clr_drv_status(wl, DISCONNECTING);
2363 WL_ERR(("error (%d)\n", err));
2364 return err;
2365 }
2366 }
2367
2368 return err;
2369}
2370
2371static s32
2372wl_cfg80211_set_tx_power(struct wiphy *wiphy,
2373 enum nl80211_tx_power_setting type, s32 dbm)
2374{
2375
2376 struct wl_priv *wl = wiphy_priv(wiphy);
2377 struct net_device *ndev = wl_to_prmry_ndev(wl);
2378 u16 txpwrmw;
2379 s32 err = 0;
2380 s32 disable = 0;
2381
2382 CHECK_SYS_UP(wl);
2383 switch (type) {
2384 case NL80211_TX_POWER_AUTOMATIC:
2385 break;
2386 case NL80211_TX_POWER_LIMITED:
2387 if (dbm < 0) {
2388 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
2389 return -EINVAL;
2390 }
2391 break;
2392 case NL80211_TX_POWER_FIXED:
2393 if (dbm < 0) {
2394 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
2395 return -EINVAL;
2396 }
2397 break;
2398 }
2399 /* Make sure radio is off or on as far as software is concerned */
2400 disable = WL_RADIO_SW_DISABLE << 16;
2401 disable = htod32(disable);
2402 err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), true);
2403 if (unlikely(err)) {
2404 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
2405 return err;
2406 }
2407
2408 if (dbm > 0xffff)
2409 txpwrmw = 0xffff;
2410 else
2411 txpwrmw = (u16) dbm;
2412 err = wl_dev_intvar_set(ndev, "qtxpower",
2413 (s32) (bcm_mw_to_qdbm(txpwrmw)));
2414 if (unlikely(err)) {
2415 WL_ERR(("qtxpower error (%d)\n", err));
2416 return err;
2417 }
2418 wl->conf->tx_power = dbm;
2419
2420 return err;
2421}
2422
2423static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
2424{
2425 struct wl_priv *wl = wiphy_priv(wiphy);
2426 struct net_device *ndev = wl_to_prmry_ndev(wl);
2427 s32 txpwrdbm;
2428 u8 result;
2429 s32 err = 0;
2430
2431 CHECK_SYS_UP(wl);
2432 err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
2433 if (unlikely(err)) {
2434 WL_ERR(("error (%d)\n", err));
2435 return err;
2436 }
2437 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
2438 *dbm = (s32) bcm_qdbm_to_mw(result);
2439
2440 return err;
2441}
2442
2443static s32
2444wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
2445 u8 key_idx, bool unicast, bool multicast)
2446{
2447 struct wl_priv *wl = wiphy_priv(wiphy);
2448 u32 index;
2449 s32 wsec;
2450 s32 err = 0;
2451 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2452
2453 WL_DBG(("key index (%d)\n", key_idx));
2454 CHECK_SYS_UP(wl);
2455 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
2456 if (unlikely(err)) {
2457 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
2458 return err;
2459 }
2460 if (wsec & WEP_ENABLED) {
2461 /* Just select a new current key */
2462 index = (u32) key_idx;
2463 index = htod32(index);
2464 err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
2465 sizeof(index), true);
2466 if (unlikely(err)) {
2467 WL_ERR(("error (%d)\n", err));
2468 }
2469 }
2470 return err;
2471}
2472
2473static s32
2474wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
2475 u8 key_idx, const u8 *mac_addr, struct key_params *params)
2476{
2477 struct wl_priv *wl = wiphy_priv(wiphy);
2478 struct wl_wsec_key key;
2479 s32 err = 0;
2480 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2481 s32 mode = get_mode_by_netdev(wl, dev);
2482 memset(&key, 0, sizeof(key));
2483 key.index = (u32) key_idx;
2484
2485 if (!ETHER_ISMULTI(mac_addr))
2486 memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN);
2487 key.len = (u32) params->key_len;
2488
2489 /* check for key index change */
2490 if (key.len == 0) {
2491 /* key delete */
2492 swap_key_from_BE(&key);
2493 wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2494 sizeof(ioctlbuf), bssidx);
2495 if (unlikely(err)) {
2496 WL_ERR(("key delete error (%d)\n", err));
2497 return err;
2498 }
2499 } else {
2500 if (key.len > sizeof(key.data)) {
2501 WL_ERR(("Invalid key length (%d)\n", key.len));
2502 return -EINVAL;
2503 }
2504 WL_DBG(("Setting the key index %d\n", key.index));
2505 memcpy(key.data, params->key, key.len);
2506
2507 if ((mode == WL_MODE_BSS) &&
2508 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
2509 u8 keybuf[8];
2510 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2511 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2512 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2513 }
2514
2515 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
2516 if (params->seq && params->seq_len == 6) {
2517 /* rx iv */
2518 u8 *ivptr;
2519 ivptr = (u8 *) params->seq;
2520 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2521 (ivptr[3] << 8) | ivptr[2];
2522 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2523 key.iv_initialized = true;
2524 }
2525
2526 switch (params->cipher) {
2527 case WLAN_CIPHER_SUITE_WEP40:
2528 key.algo = CRYPTO_ALGO_WEP1;
2529 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
2530 break;
2531 case WLAN_CIPHER_SUITE_WEP104:
2532 key.algo = CRYPTO_ALGO_WEP128;
2533 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
2534 break;
2535 case WLAN_CIPHER_SUITE_TKIP:
2536 key.algo = CRYPTO_ALGO_TKIP;
2537 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
2538 break;
2539 case WLAN_CIPHER_SUITE_AES_CMAC:
2540 key.algo = CRYPTO_ALGO_AES_CCM;
2541 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
2542 break;
2543 case WLAN_CIPHER_SUITE_CCMP:
2544 key.algo = CRYPTO_ALGO_AES_CCM;
2545 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
2546 break;
2547 default:
2548 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
2549 return -EINVAL;
2550 }
2551 swap_key_from_BE(&key);
2552#ifdef CONFIG_WIRELESS_EXT
2553 dhd_wait_pend8021x(dev);
2554#endif
2555 wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2556 sizeof(ioctlbuf), bssidx);
2557 if (unlikely(err)) {
2558 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2559 return err;
2560 }
2561 }
2562 return err;
2563}
2564
2565static s32
2566wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
2567 u8 key_idx, bool pairwise, const u8 *mac_addr,
2568 struct key_params *params)
2569{
2570 struct wl_wsec_key key;
2571 s32 val = 0;
2572 s32 wsec = 0;
2573 s32 err = 0;
2574 u8 keybuf[8];
2575 s32 bssidx = 0;
2576 struct wl_priv *wl = wiphy_priv(wiphy);
2577 s32 mode = get_mode_by_netdev(wl, dev);
2578 WL_DBG(("key index (%d)\n", key_idx));
2579 CHECK_SYS_UP(wl);
2580
2581 bssidx = wl_cfgp2p_find_idx(wl, dev);
2582
2583 if (mac_addr) {
2584 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
2585 goto exit;
2586 }
2587 memset(&key, 0, sizeof(key));
2588
2589 key.len = (u32) params->key_len;
2590 key.index = (u32) key_idx;
2591
2592 if (unlikely(key.len > sizeof(key.data))) {
2593 WL_ERR(("Too long key length (%u)\n", key.len));
2594 return -EINVAL;
2595 }
2596 memcpy(key.data, params->key, key.len);
2597
2598 key.flags = WL_PRIMARY_KEY;
2599 switch (params->cipher) {
2600 case WLAN_CIPHER_SUITE_WEP40:
2601 key.algo = CRYPTO_ALGO_WEP1;
2602 val = WEP_ENABLED;
2603 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
2604 break;
2605 case WLAN_CIPHER_SUITE_WEP104:
2606 key.algo = CRYPTO_ALGO_WEP128;
2607 val = WEP_ENABLED;
2608 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
2609 break;
2610 case WLAN_CIPHER_SUITE_TKIP:
2611 key.algo = CRYPTO_ALGO_TKIP;
2612 val = TKIP_ENABLED;
2613 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
2614 if (mode == WL_MODE_BSS) {
2615 bcopy(&key.data[24], keybuf, sizeof(keybuf));
2616 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
2617 bcopy(keybuf, &key.data[16], sizeof(keybuf));
2618 }
2619 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
2620 break;
2621 case WLAN_CIPHER_SUITE_AES_CMAC:
2622 key.algo = CRYPTO_ALGO_AES_CCM;
2623 val = AES_ENABLED;
2624 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
2625 break;
2626 case WLAN_CIPHER_SUITE_CCMP:
2627 key.algo = CRYPTO_ALGO_AES_CCM;
2628 val = AES_ENABLED;
2629 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
2630 break;
2631 default:
2632 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
2633 return -EINVAL;
2634 }
2635
2636 /* Set the new key/index */
2637 swap_key_from_BE(&key);
2638 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2639 sizeof(ioctlbuf), bssidx);
2640 if (unlikely(err)) {
2641 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2642 return err;
2643 }
2644
2645exit:
2646 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
2647 if (unlikely(err)) {
2648 WL_ERR(("get wsec error (%d)\n", err));
2649 return err;
2650 }
2651
2652 wsec |= val;
2653 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
2654 if (unlikely(err)) {
2655 WL_ERR(("set wsec error (%d)\n", err));
2656 return err;
2657 }
2658
2659 return err;
2660}
2661
2662static s32
2663wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
2664 u8 key_idx, bool pairwise, const u8 *mac_addr)
2665{
2666 struct wl_wsec_key key;
2667 struct wl_priv *wl = wiphy_priv(wiphy);
2668 s32 err = 0;
2669 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2670
2671 WL_DBG(("Enter\n"));
2672 CHECK_SYS_UP(wl);
2673 memset(&key, 0, sizeof(key));
2674
2675 key.index = (u32) key_idx;
2676 key.flags = WL_PRIMARY_KEY;
2677 key.algo = CRYPTO_ALGO_OFF;
2678
2679 WL_DBG(("key index (%d)\n", key_idx));
2680 /* Set the new key/index */
2681 swap_key_from_BE(&key);
2682 wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2683 sizeof(ioctlbuf), bssidx);
2684 if (unlikely(err)) {
2685 if (err == -EINVAL) {
2686 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
2687 /* we ignore this key index in this case */
2688 WL_DBG(("invalid key index (%d)\n", key_idx));
2689 }
2690 } else {
2691 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2692 }
2693 return err;
2694 }
2695 return err;
2696}
2697
2698static s32
2699wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
2700 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2701 void (*callback) (void *cookie, struct key_params * params))
2702{
2703 struct key_params params;
2704 struct wl_wsec_key key;
2705 struct wl_priv *wl = wiphy_priv(wiphy);
2706 struct wl_security *sec;
2707 s32 wsec;
2708 s32 err = 0;
2709 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2710
2711 WL_DBG(("key index (%d)\n", key_idx));
2712 CHECK_SYS_UP(wl);
2713 memset(&key, 0, sizeof(key));
2714 key.index = key_idx;
2715 swap_key_to_BE(&key);
2716 memset(&params, 0, sizeof(params));
2717 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
2718 memcpy(params.key, key.data, params.key_len);
2719
2720 wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
2721 if (unlikely(err)) {
2722 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
2723 return err;
2724 }
2725 switch (wsec & ~SES_OW_ENABLED) {
2726 case WEP_ENABLED:
2727 sec = wl_read_prof(wl, WL_PROF_SEC);
2728 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2729 params.cipher = WLAN_CIPHER_SUITE_WEP40;
2730 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
2731 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2732 params.cipher = WLAN_CIPHER_SUITE_WEP104;
2733 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
2734 }
2735 break;
2736 case TKIP_ENABLED:
2737 params.cipher = WLAN_CIPHER_SUITE_TKIP;
2738 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
2739 break;
2740 case AES_ENABLED:
2741 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
2742 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
2743 break;
2744 default:
2745 WL_ERR(("Invalid algo (0x%x)\n", wsec));
2746 return -EINVAL;
2747 }
2748
2749 callback(cookie, &params);
2750 return err;
2751}
2752
2753static s32
2754wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2755 struct net_device *dev, u8 key_idx)
2756{
2757 WL_INFO(("Not supported\n"));
2758 return -EOPNOTSUPP;
2759}
2760
2761static s32
2762wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
2763 u8 *mac, struct station_info *sinfo)
2764{
2765 struct wl_priv *wl = wiphy_priv(wiphy);
2766 scb_val_t scb_val;
2767 s32 rssi;
2768 s32 rate;
2769 s32 err = 0;
2770 sta_info_t *sta;
2771#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2772 s8 eabuf[ETHER_ADDR_STR_LEN];
2773#endif
2774 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
2775
2776 CHECK_SYS_UP(wl);
2777 if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
2778 err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
2779 ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
2780 if (err < 0) {
2781 WL_ERR(("GET STA INFO failed, %d\n", err));
2782 return err;
2783 }
2784 sinfo->filled = STATION_INFO_INACTIVE_TIME;
2785 sta = (sta_info_t *)ioctlbuf;
2786 sta->len = dtoh16(sta->len);
2787 sta->cap = dtoh16(sta->cap);
2788 sta->flags = dtoh32(sta->flags);
2789 sta->idle = dtoh32(sta->idle);
2790 sta->in = dtoh32(sta->in);
2791 sinfo->inactive_time = sta->idle * 1000;
2792#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2793 if (sta->flags & WL_STA_ASSOC) {
2794 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
2795 sinfo->connected_time = sta->in;
2796 }
2797 WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n",
2798 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
2799 sta->idle * 1000));
2800#endif
2801 } else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
2802 u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID);
2803
2804 if (!wl_get_drv_status(wl, CONNECTED) ||
2805 (dhd_is_associated(dhd, NULL) == FALSE)) {
2806 WL_ERR(("NOT assoc\n"));
2807 err = -ENODEV;
2808 goto get_station_err;
2809 }
2810 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
2811 WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
2812 MAC2STR(mac), MAC2STR(curmacp)));
2813 }
2814
2815 /* Report the current tx rate */
2816 err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
2817 if (err) {
2818 WL_ERR(("Could not get rate (%d)\n", err));
2819 } else {
2820 rate = dtoh32(rate);
2821 sinfo->filled |= STATION_INFO_TX_BITRATE;
2822 sinfo->txrate.legacy = rate * 5;
2823 WL_DBG(("Rate %d Mbps\n", (rate / 2)));
2824 }
2825
2826 memset(&scb_val, 0, sizeof(scb_val));
2827 scb_val.val = 0;
2828 err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
2829 sizeof(scb_val_t), false);
2830 if (err) {
2831 WL_ERR(("Could not get rssi (%d)\n", err));
2832 goto get_station_err;
2833 }
2834
2835 rssi = dtoh32(scb_val.val);
2836 sinfo->filled |= STATION_INFO_SIGNAL;
2837 sinfo->signal = rssi;
2838 WL_DBG(("RSSI %d dBm\n", rssi));
2839
2840get_station_err:
2841 if (err) {
2842 /* Disconnect due to zero BSSID or error to get RSSI */
2843 WL_ERR(("force cfg80211_disconnected\n"));
2844 wl_clr_drv_status(wl, CONNECTED);
2845 cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
2846 wl_link_down(wl);
2847 }
2848 }
2849
2850 return err;
2851}
2852
2853static s32
2854wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
2855 bool enabled, s32 timeout)
2856{
2857 s32 pm;
2858 s32 err = 0;
2859 struct wl_priv *wl = wiphy_priv(wiphy);
2860
2861 CHECK_SYS_UP(wl);
2862 pm = enabled ? PM_FAST : PM_OFF;
2863 /* Do not enable the power save after assoc if it is p2p interface */
2864 if (wl->p2p && wl->p2p->vif_created) {
2865 WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n"));
2866 pm = PM_OFF;
2867 }
2868 pm = htod32(pm);
2869 WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
2870 err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
2871 if (unlikely(err)) {
2872 if (err == -ENODEV)
2873 WL_DBG(("net_device is not ready yet\n"));
2874 else
2875 WL_ERR(("error (%d)\n", err));
2876 return err;
2877 }
2878 return err;
2879}
2880
2881static __used u32 wl_find_msb(u16 bit16)
2882{
2883 u32 ret = 0;
2884
2885 if (bit16 & 0xff00) {
2886 ret += 8;
2887 bit16 >>= 8;
2888 }
2889
2890 if (bit16 & 0xf0) {
2891 ret += 4;
2892 bit16 >>= 4;
2893 }
2894
2895 if (bit16 & 0xc) {
2896 ret += 2;
2897 bit16 >>= 2;
2898 }
2899
2900 if (bit16 & 2)
2901 ret += bit16 & 2;
2902 else if (bit16)
2903 ret += bit16;
2904
2905 return ret;
2906}
2907
2908static s32 wl_cfg80211_resume(struct wiphy *wiphy)
2909{
2910 struct wl_priv *wl = wiphy_priv(wiphy);
2911 s32 err = 0;
2912
2913 if (unlikely(!wl_get_drv_status(wl, READY))) {
2914 WL_INFO(("device is not ready : status (%d)\n",
2915 (int)wl->status));
2916 return 0;
2917 }
2918
2919 wl_invoke_iscan(wl);
2920
2921 return err;
2922}
2923
2924#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
2925static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
2926#else
2927static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
2928#endif
2929{
2930#ifdef DHD_CLEAR_ON_SUSPEND
2931 struct wl_priv *wl = wiphy_priv(wiphy);
2932 struct net_device *ndev = wl_to_prmry_ndev(wl);
2933 unsigned long flags;
2934
2935 if (unlikely(!wl_get_drv_status(wl, READY))) {
2936 WL_INFO(("device is not ready : status (%d)\n",
2937 (int)wl->status));
2938 return 0;
2939 }
2940
2941 wl_set_drv_status(wl, SCAN_ABORTING);
2942 wl_term_iscan(wl);
2943 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
2944 if (wl->scan_request) {
2945 cfg80211_scan_done(wl->scan_request, true);
2946 wl->scan_request = NULL;
2947 }
2948 wl_clr_drv_status(wl, SCANNING);
2949 wl_clr_drv_status(wl, SCAN_ABORTING);
2950 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
2951 if (wl_get_drv_status(wl, CONNECTING)) {
2952 wl_bss_connect_done(wl, ndev, NULL, NULL, false);
2953 }
2954#endif
2955 return 0;
2956}
2957
2958static __used s32
2959wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
2960 s32 err)
2961{
2962 int i, j;
2963 struct wl_priv *wl = wlcfg_drv_priv;
2964 struct net_device *primary_dev = wl_to_prmry_ndev(wl);
2965
2966 /* Firmware is supporting pmk list only for STA interface i.e. primary interface
2967 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
2968 * Do we really need to support PMK cache in P2P in firmware?
2969 */
2970 if (primary_dev != dev) {
2971 WL_INFO(("Not supporting Flushing pmklist on virtual"
2972 " interfaces than primary interface\n"));
2973 return err;
2974 }
2975
2976 WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
2977 for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
2978 WL_DBG(("PMKID[%d]: %pM =\n", i,
2979 &pmk_list->pmkids.pmkid[i].BSSID));
2980 for (j = 0; j < WPA2_PMKID_LEN; j++) {
2981 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
2982 }
2983 }
2984 if (likely(!err)) {
2985 err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
2986 sizeof(*pmk_list));
2987 }
2988
2989 return err;
2990}
2991
2992static s32
2993wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
2994 struct cfg80211_pmksa *pmksa)
2995{
2996 struct wl_priv *wl = wiphy_priv(wiphy);
2997 s32 err = 0;
2998 int i;
2999
3000 CHECK_SYS_UP(wl);
3001 for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
3002 if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
3003 ETHER_ADDR_LEN))
3004 break;
3005 if (i < WL_NUM_PMKIDS_MAX) {
3006 memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
3007 ETHER_ADDR_LEN);
3008 memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
3009 WPA2_PMKID_LEN);
3010 if (i == wl->pmk_list->pmkids.npmkid)
3011 wl->pmk_list->pmkids.npmkid++;
3012 } else {
3013 err = -EINVAL;
3014 }
3015 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
3016 &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID));
3017 for (i = 0; i < WPA2_PMKID_LEN; i++) {
3018 WL_DBG(("%02x\n",
3019 wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].
3020 PMKID[i]));
3021 }
3022
3023 err = wl_update_pmklist(dev, wl->pmk_list, err);
3024
3025 return err;
3026}
3027
3028static s32
3029wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
3030 struct cfg80211_pmksa *pmksa)
3031{
3032 struct wl_priv *wl = wiphy_priv(wiphy);
3033 struct _pmkid_list pmkid;
3034 s32 err = 0;
3035 int i;
3036
3037 CHECK_SYS_UP(wl);
3038 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
3039 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
3040
3041 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3042 &pmkid.pmkid[0].BSSID));
3043 for (i = 0; i < WPA2_PMKID_LEN; i++) {
3044 WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
3045 }
3046
3047 for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
3048 if (!memcmp
3049 (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
3050 ETHER_ADDR_LEN))
3051 break;
3052
3053 if ((wl->pmk_list->pmkids.npmkid > 0) &&
3054 (i < wl->pmk_list->pmkids.npmkid)) {
3055 memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
3056 for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) {
3057 memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID,
3058 &wl->pmk_list->pmkids.pmkid[i + 1].BSSID,
3059 ETHER_ADDR_LEN);
3060 memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID,
3061 &wl->pmk_list->pmkids.pmkid[i + 1].PMKID,
3062 WPA2_PMKID_LEN);
3063 }
3064 wl->pmk_list->pmkids.npmkid--;
3065 } else {
3066 err = -EINVAL;
3067 }
3068
3069 err = wl_update_pmklist(dev, wl->pmk_list, err);
3070
3071 return err;
3072
3073}
3074
3075static s32
3076wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
3077{
3078 struct wl_priv *wl = wiphy_priv(wiphy);
3079 s32 err = 0;
3080 CHECK_SYS_UP(wl);
3081 memset(wl->pmk_list, 0, sizeof(*wl->pmk_list));
3082 err = wl_update_pmklist(dev, wl->pmk_list, err);
3083 return err;
3084
3085}
3086
3087wl_scan_params_t *
3088wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
3089{
3090 wl_scan_params_t *params;
3091 int params_size;
3092 int num_chans;
3093
3094 *out_params_size = 0;
3095
3096 /* Our scan params only need space for 1 channel and 0 ssids */
3097 params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
3098 params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
3099 if (params == NULL) {
3100 WL_ERR(("%s: mem alloc failed (%d bytes)\n", __func__, params_size));
3101 return params;
3102 }
3103 memset(params, 0, params_size);
3104 params->nprobes = nprobes;
3105
3106 num_chans = (channel == 0) ? 0 : 1;
3107
3108 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
3109 params->bss_type = DOT11_BSSTYPE_ANY;
3110 params->scan_type = DOT11_SCANTYPE_ACTIVE;
3111 params->nprobes = htod32(1);
3112 params->active_time = htod32(-1);
3113 params->passive_time = htod32(-1);
3114 params->home_time = htod32(10);
3115 params->channel_list[0] = htodchanspec(channel);
3116
3117 /* Our scan params have 1 channel and 0 ssids */
3118 params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
3119 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
3120
3121 *out_params_size = params_size; /* rtn size to the caller */
3122 return params;
3123}
3124
3125s32
3126wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
3127{
3128 wl_scan_params_t *params = NULL;
3129 s32 params_size = 0;
3130 s32 err = BCME_OK;
3131 unsigned long flags;
3132
3133 WL_DBG(("Enter\n"));
3134
3135 /* Our scan params only need space for 1 channel and 0 ssids */
3136 params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
3137 if (params == NULL) {
3138 WL_ERR(("scan params allocation failed \n"));
3139 err = -ENOMEM;
3140 } else {
3141 /* Do a scan abort to stop the driver's scan engine */
3142 err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
3143 if (err < 0) {
3144 WL_ERR(("scan abort failed \n"));
3145 }
3146 }
3147 del_timer_sync(&wl->scan_timeout);
3148 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
3149 if (wl->scan_request) {
3150 cfg80211_scan_done(wl->scan_request, true);
3151 wl->scan_request = NULL;
3152 }
3153 wl_clr_drv_status(wl, SCANNING);
3154 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
3155 if (params)
3156 kfree(params);
3157 return err;
3158}
3159
3160static s32
3161wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
3162 struct ieee80211_channel * channel,
3163 enum nl80211_channel_type channel_type,
3164 unsigned int duration, u64 *cookie)
3165{
3166 s32 target_channel;
3167
3168 s32 err = BCME_OK;
3169 struct wl_priv *wl = wiphy_priv(wiphy);
3170 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
3171 WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
3172 if (likely(wl_get_drv_status(wl, SCANNING))) {
3173 wl_cfg80211_scan_abort(wl, dev);
3174 }
3175
3176 target_channel = ieee80211_frequency_to_channel(channel->center_freq);
3177 memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
3178 wl->remain_on_chan_type = channel_type;
3179 wl->cache_cookie = *cookie;
3180 cfg80211_ready_on_channel(dev, *cookie, channel,
3181 channel_type, duration, GFP_KERNEL);
3182 if (!p2p_on(wl)) {
3183 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
3184
3185 /* In case of p2p_listen command, supplicant send remain_on_channel
3186 * without turning on P2P
3187 */
3188
3189 p2p_on(wl) = true;
3190 err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
3191
3192 if (unlikely(err)) {
3193 goto exit;
3194 }
3195 }
3196 if (p2p_on(wl))
3197 wl_cfgp2p_discover_listen(wl, target_channel, duration);
3198
3199
3200exit:
3201 return err;
3202}
3203
3204static s32
3205wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
3206 u64 cookie)
3207{
3208 s32 err = 0;
3209 WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex));
3210 return err;
3211}
3212
3213static s32
3214wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
3215 struct ieee80211_channel *channel, bool offchan,
3216 enum nl80211_channel_type channel_type,
3217 bool channel_type_valid, unsigned int wait,
3218 const u8* buf, size_t len, u64 *cookie)
3219{
3220 wl_action_frame_t *action_frame;
3221 wl_af_params_t *af_params;
3222 wifi_p2p_ie_t *p2p_ie;
3223 wpa_ie_fixed_t *wps_ie;
3224 const struct ieee80211_mgmt *mgmt;
3225 struct wl_priv *wl = wiphy_priv(wiphy);
3226 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
3227 s32 err = BCME_OK;
3228 s32 bssidx = 0;
3229 u32 p2pie_len = 0;
3230 u32 wpsie_len = 0;
3231 u16 fc;
3232 bool ack = false;
3233 wifi_p2p_pub_act_frame_t *act_frm;
3234 WL_DBG(("Enter \n"));
3235 /* find bssidx based on ndev */
3236 bssidx = wl_cfgp2p_find_idx(wl, dev);
3237 /* cookie generation */
3238 *cookie = (unsigned long) buf;
3239
3240 if (bssidx == -1) {
3241
3242 WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
3243 return -ENODEV;
3244 }
3245 if (wl->p2p_supported && p2p_on(wl)) {
3246 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
3247 /* Suspend P2P discovery search-listen to prevent it from changing the
3248 * channel.
3249 */
3250 if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) {
3251 WL_ERR(("Can not disable discovery mode\n"));
3252 return -EFAULT;
3253 }
3254 }
3255
3256 mgmt = (const struct ieee80211_mgmt *) buf;
3257 fc = mgmt->frame_control;
3258 if (fc != IEEE80211_STYPE_ACTION) {
3259 if (fc == IEEE80211_STYPE_PROBE_RESP) {
3260 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3261 s32 ie_len = len - ie_offset;
3262 if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
3263 != NULL) {
3264 /* Total length of P2P Information Element */
3265 p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
3266 /* Have to change p2p device address in dev_info attribute
3267 * because Supplicant use primary eth0 address
3268 */
3269 #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
3270 wl_cfg80211_change_ifaddr((u8 *)p2p_ie,
3271 &wl->p2p_dev_addr, P2P_SEID_DEV_INFO);
3272 #endif
3273 }
3274 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len))
3275 != NULL) {
3276 /* Order of Vendor IE is 1) WPS IE +
3277 * 2) P2P IE created by supplicant
3278 * So, it is ok to find start address of WPS IE
3279 * to save IEs to firmware
3280 */
3281 wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
3282 sizeof(wps_ie->tag);
3283 wl_cfgp2p_set_management_ie(wl, dev, bssidx,
3284 VNDR_IE_PRBRSP_FLAG,
3285 (u8 *)wps_ie, wpsie_len + p2pie_len);
3286 }
3287 }
3288 cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
3289 goto exit;
3290 } else {
3291 /* Abort the dwell time of any previous off-channel action frame that may
3292 * be still in effect. Sending off-channel action frames relies on the
3293 * driver's scan engine. If a previous off-channel action frame tx is
3294 * still in progress (including the dwell time), then this new action
3295 * frame will not be sent out.
3296 */
3297 wl_cfg80211_scan_abort(wl, dev);
3298 }
3299 af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
3300
3301 if (af_params == NULL)
3302 {
3303 WL_ERR(("unable to allocate frame\n"));
3304 return -ENOMEM;
3305 }
3306
3307 action_frame = &af_params->action_frame;
3308
3309 /* Add the packet Id */
3310 action_frame->packetId = (u32) action_frame;
3311 WL_DBG(("action frame %d\n", action_frame->packetId));
3312 /* Add BSSID */
3313 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
3314 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
3315
3316 /* Add the length exepted for 802.11 header */
3317 action_frame->len = len - DOT11_MGMT_HDR_LEN;
3318 WL_DBG(("action_frame->len: %d\n", action_frame->len));
3319
3320 /* Add the channel */
3321 af_params->channel =
3322 ieee80211_frequency_to_channel(channel->center_freq);
3323
3324 /* Add the dwell time
3325 * Dwell time to stay off-channel to wait for a response action frame
3326 * after transmitting an GO Negotiation action frame
3327 */
3328 af_params->dwell_time = WL_DWELL_TIME;
3329
3330 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
3331
3332 act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
3333 WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
3334 action_frame->len, af_params->channel,
3335 act_frm->category, act_frm->subtype));
3336 if (wl->p2p->vif_created) {
3337 /*
3338 * To make sure to send successfully action frame, we have to turn off mpc
3339 */
3340 if ((act_frm->subtype == P2P_PAF_GON_REQ)||
3341 (act_frm->subtype == P2P_PAF_GON_RSP)) {
3342 wldev_iovar_setint(dev, "mpc", 0);
3343 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
3344 wldev_iovar_setint(dev, "mpc", 1);
3345 } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
3346 af_params->dwell_time = WL_LONG_DWELL_TIME;
3347 }
3348 }
3349
3350 ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
3351 cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL);
3352
3353 kfree(af_params);
3354exit:
3355 return err;
3356}
3357
3358
3359static void
3360wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev,
3361 u16 frame_type, bool reg)
3362{
3363
3364 WL_DBG(("%s: frame_type: %x, reg: %d\n", __func__, frame_type, reg));
3365
3366 if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
3367 return;
3368
3369 return;
3370}
3371
3372
3373static s32
3374wl_cfg80211_change_bss(struct wiphy *wiphy,
3375 struct net_device *dev,
3376 struct bss_parameters *params)
3377{
3378 if (params->use_cts_prot >= 0) {
3379 }
3380
3381 if (params->use_short_preamble >= 0) {
3382 }
3383
3384 if (params->use_short_slot_time >= 0) {
3385 }
3386
3387 if (params->basic_rates) {
3388 }
3389
3390 if (params->ap_isolate >= 0) {
3391 }
3392
3393 if (params->ht_opmode >= 0) {
3394 }
3395
3396 return 0;
3397}
3398
3399static s32
3400wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
3401 struct ieee80211_channel *chan,
3402 enum nl80211_channel_type channel_type)
3403{
3404 s32 channel;
3405 s32 err = BCME_OK;
3406
3407 channel = ieee80211_frequency_to_channel(chan->center_freq);
3408 WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
3409 dev->ifindex, channel_type, channel));
3410 err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true);
3411 if (err < 0) {
3412 WL_ERR(("WLC_SET_CHANNEL error %d chip may not be supporting this channel\n", err));
3413 }
3414 return err;
3415}
3416
3417static s32
3418wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
3419{
3420 s32 len = 0;
3421 s32 err = BCME_OK;
3422 u16 auth = 0; /* d11 open authentication */
3423 u16 count;
3424 u32 wsec;
3425 u32 pval = 0;
3426 u32 gval = 0;
3427 u32 wpa_auth = 0;
3428 u8* tmp;
3429 wpa_suite_mcast_t *mcast;
3430 wpa_suite_ucast_t *ucast;
3431 wpa_suite_auth_key_mgmt_t *mgmt;
3432 if (wpa2ie == NULL)
3433 goto exit;
3434
3435 WL_DBG(("Enter \n"));
3436 len = wpa2ie->len;
3437 /* check the mcast cipher */
3438 mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
3439 tmp = mcast->oui;
3440 switch (tmp[DOT11_OUI_LEN]) {
3441 case WPA_CIPHER_NONE:
3442 gval = 0;
3443 break;
3444 case WPA_CIPHER_WEP_40:
3445 case WPA_CIPHER_WEP_104:
3446 gval = WEP_ENABLED;
3447 break;
3448 case WPA_CIPHER_TKIP:
3449 gval = TKIP_ENABLED;
3450 break;
3451 case WPA_CIPHER_AES_CCM:
3452 gval = AES_ENABLED;
3453 break;
3454 default:
3455 WL_ERR(("No Security Info\n"));
3456 break;
3457 }
3458 len -= WPA_SUITE_LEN;
3459 /* check the unicast cipher */
3460 ucast = (wpa_suite_ucast_t *)&mcast[1];
3461 count = ltoh16_ua(&ucast->count);
3462 tmp = ucast->list[0].oui;
3463 switch (tmp[DOT11_OUI_LEN]) {
3464 case WPA_CIPHER_NONE:
3465 pval = 0;
3466 break;
3467 case WPA_CIPHER_WEP_40:
3468 case WPA_CIPHER_WEP_104:
3469 pval = WEP_ENABLED;
3470 break;
3471 case WPA_CIPHER_TKIP:
3472 pval = TKIP_ENABLED;
3473 break;
3474 case WPA_CIPHER_AES_CCM:
3475 pval = AES_ENABLED;
3476 break;
3477 default:
3478 WL_ERR(("No Security Info\n"));
3479 }
3480 /* FOR WPS , set SEC_OW_ENABLED */
3481 wsec = (pval | gval | SES_OW_ENABLED);
3482 /* check the AKM */
3483 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1];
3484 count = ltoh16_ua(&mgmt->count);
3485 tmp = (u8 *)&mgmt->list[0];
3486 switch (tmp[DOT11_OUI_LEN]) {
3487 case RSN_AKM_NONE:
3488 wpa_auth = WPA_AUTH_NONE;
3489 break;
3490 case RSN_AKM_UNSPECIFIED:
3491 wpa_auth = WPA2_AUTH_UNSPECIFIED;
3492 break;
3493 case RSN_AKM_PSK:
3494 wpa_auth = WPA2_AUTH_PSK;
3495 break;
3496 default:
3497 WL_ERR(("No Key Mgmt Info\n"));
3498 }
3499 /* set auth */
3500 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
3501 if (err < 0) {
3502 WL_ERR(("auth error %d\n", err));
3503 return BCME_ERROR;
3504 }
3505 /* set wsec */
3506 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
3507 if (err < 0) {
3508 WL_ERR(("wsec error %d\n", err));
3509 return BCME_ERROR;
3510 }
3511 /* set upper-layer auth */
3512 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
3513 if (err < 0) {
3514 WL_ERR(("wpa_auth error %d\n", err));
3515 return BCME_ERROR;
3516 }
3517exit:
3518 return 0;
3519}
3520
3521static s32
3522wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
3523{
3524 wpa_suite_mcast_t *mcast;
3525 wpa_suite_ucast_t *ucast;
3526 wpa_suite_auth_key_mgmt_t *mgmt;
3527 u16 auth = 0; /* d11 open authentication */
3528 u16 count;
3529 s32 err = BCME_OK;
3530 s32 len = 0;
3531 u32 i;
3532 u32 wsec;
3533 u32 pval = 0;
3534 u32 gval = 0;
3535 u32 wpa_auth = 0;
3536 u32 tmp = 0;
3537
3538 if (wpaie == NULL)
3539 goto exit;
3540 WL_DBG(("Enter \n"));
3541 len = wpaie->length; /* value length */
3542 len -= WPA_IE_TAG_FIXED_LEN;
3543 /* check for multicast cipher suite */
3544 if (len < WPA_SUITE_LEN) {
3545 WL_INFO(("no multicast cipher suite\n"));
3546 goto exit;
3547 }
3548
3549 /* pick up multicast cipher */
3550 mcast = (wpa_suite_mcast_t *)&wpaie[1];
3551 len -= WPA_SUITE_LEN;
3552 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
3553 if (IS_WPA_CIPHER(mcast->type)) {
3554 tmp = 0;
3555 switch (mcast->type) {
3556 case WPA_CIPHER_NONE:
3557 tmp = 0;
3558 break;
3559 case WPA_CIPHER_WEP_40:
3560 case WPA_CIPHER_WEP_104:
3561 tmp = WEP_ENABLED;
3562 break;
3563 case WPA_CIPHER_TKIP:
3564 tmp = TKIP_ENABLED;
3565 break;
3566 case WPA_CIPHER_AES_CCM:
3567 tmp = AES_ENABLED;
3568 break;
3569 default:
3570 WL_ERR(("No Security Info\n"));
3571 }
3572 gval |= tmp;
3573 }
3574 }
3575 /* Check for unicast suite(s) */
3576 if (len < WPA_IE_SUITE_COUNT_LEN) {
3577 WL_INFO(("no unicast suite\n"));
3578 goto exit;
3579 }
3580 /* walk thru unicast cipher list and pick up what we recognize */
3581 ucast = (wpa_suite_ucast_t *)&mcast[1];
3582 count = ltoh16_ua(&ucast->count);
3583 len -= WPA_IE_SUITE_COUNT_LEN;
3584 for (i = 0; i < count && len >= WPA_SUITE_LEN;
3585 i++, len -= WPA_SUITE_LEN) {
3586 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
3587 if (IS_WPA_CIPHER(ucast->list[i].type)) {
3588 tmp = 0;
3589 switch (ucast->list[i].type) {
3590 case WPA_CIPHER_NONE:
3591 tmp = 0;
3592 break;
3593 case WPA_CIPHER_WEP_40:
3594 case WPA_CIPHER_WEP_104:
3595 tmp = WEP_ENABLED;
3596 break;
3597 case WPA_CIPHER_TKIP:
3598 tmp = TKIP_ENABLED;
3599 break;
3600 case WPA_CIPHER_AES_CCM:
3601 tmp = AES_ENABLED;
3602 break;
3603 default:
3604 WL_ERR(("No Security Info\n"));
3605 }
3606 pval |= tmp;
3607 }
3608 }
3609 }
3610 len -= (count - i) * WPA_SUITE_LEN;
3611 /* Check for auth key management suite(s) */
3612 if (len < WPA_IE_SUITE_COUNT_LEN) {
3613 WL_INFO((" no auth key mgmt suite\n"));
3614 goto exit;
3615 }
3616 /* walk thru auth management suite list and pick up what we recognize */
3617 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
3618 count = ltoh16_ua(&mgmt->count);
3619 len -= WPA_IE_SUITE_COUNT_LEN;
3620 for (i = 0; i < count && len >= WPA_SUITE_LEN;
3621 i++, len -= WPA_SUITE_LEN) {
3622 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
3623 if (IS_WPA_AKM(mgmt->list[i].type)) {
3624 tmp = 0;
3625 switch (mgmt->list[i].type) {
3626 case RSN_AKM_NONE:
3627 tmp = WPA_AUTH_NONE;
3628 break;
3629 case RSN_AKM_UNSPECIFIED:
3630 tmp = WPA_AUTH_UNSPECIFIED;
3631 break;
3632 case RSN_AKM_PSK:
3633 tmp = WPA_AUTH_PSK;
3634 break;
3635 default:
3636 WL_ERR(("No Key Mgmt Info\n"));
3637 }
3638 wpa_auth |= tmp;
3639 }
3640 }
3641
3642 }
3643 /* FOR WPS , set SEC_OW_ENABLED */
3644 wsec = (pval | gval | SES_OW_ENABLED);
3645 /* set auth */
3646 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
3647 if (err < 0) {
3648 WL_ERR(("auth error %d\n", err));
3649 return BCME_ERROR;
3650 }
3651 /* set wsec */
3652 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
3653 if (err < 0) {
3654 WL_ERR(("wsec error %d\n", err));
3655 return BCME_ERROR;
3656 }
3657 /* set upper-layer auth */
3658 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
3659 if (err < 0) {
3660 WL_ERR(("wpa_auth error %d\n", err));
3661 return BCME_ERROR;
3662 }
3663exit:
3664 return 0;
3665}
3666
3667static s32
3668wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
3669 struct beacon_parameters *info)
3670{
3671 s32 err = BCME_OK;
3672 bcm_tlv_t *ssid_ie;
3673 wlc_ssid_t ssid;
3674 struct wl_priv *wl = wiphy_priv(wiphy);
3675 struct wl_join_params join_params;
3676 wpa_ie_fixed_t *wps_ie;
3677 wpa_ie_fixed_t *wpa_ie;
3678 bcm_tlv_t *wpa2_ie;
3679 wifi_p2p_ie_t *p2p_ie;
3680 bool is_bssup = false;
3681 bool update_bss = false;
3682 bool pbc = false;
3683 u16 wpsie_len = 0;
3684 u16 p2pie_len = 0;
3685 u8 beacon_ie[IE_MAX_LEN];
3686 s32 ie_offset = 0;
3687 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
3688 s32 infra = 1;
3689 s32 join_params_size = 0;
3690 s32 ap = 0;
3691 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
3692 info->interval, info->dtim_period, info->head_len, info->tail_len));
3693 if (wl->p2p_supported && p2p_on(wl) &&
3694 (bssidx == wl_to_p2p_bss_bssidx(wl,
3695 P2PAPI_BSSCFG_CONNECTION))) {
3696 memset(beacon_ie, 0, sizeof(beacon_ie));
3697 /* We don't need to set beacon for P2P_GO,
3698 * but need to parse ssid from beacon_parameters
3699 * because there is no way to set ssid
3700 */
3701 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3702 /* find the SSID */
3703 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
3704 info->head_len - ie_offset,
3705 DOT11_MNG_SSID_ID)) != NULL) {
3706 memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len);
3707 wl->p2p->ssid.SSID_len = ssid_ie->len;
3708 WL_DBG(("SSID (%s) in Head \n", ssid_ie->data));
3709
3710 } else {
3711 WL_ERR(("No SSID in beacon \n"));
3712 }
3713
3714 /* find the WPSIE */
3715 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
3716 wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
3717 /*
3718 * Should be compared with saved ie before saving it
3719 */
3720 wl_validate_wps_ie((char *) wps_ie, &pbc);
3721 memcpy(beacon_ie, wps_ie, wpsie_len);
3722 } else {
3723 WL_ERR(("No WPSIE in beacon \n"));
3724 }
3725
3726
3727 /* find the P2PIE */
3728 if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) {
3729 /* Total length of P2P Information Element */
3730 p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
3731 #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
3732 /* Have to change device address in dev_id attribute because Supplicant
3733 * use primary eth0 address
3734 */
3735 wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID);
3736 #endif
3737 memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len);
3738
3739 } else {
3740 WL_ERR(("No P2PIE in beacon \n"));
3741 }
3742 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3743 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3744 wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
3745 beacon_ie, wpsie_len + p2pie_len);
3746
3747 /* find the RSN_IE */
3748 if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
3749 DOT11_MNG_RSN_ID)) != NULL) {
3750 WL_DBG((" WPA2 IE is found\n"));
3751 }
3752 is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
3753
3754 if (!is_bssup && (wpa2_ie != NULL)) {
3755 wldev_iovar_setint(dev, "mpc", 0);
3756 if ((err = wl_validate_wpa2ie(dev, wpa2_ie, bssidx)) < 0) {
3757 WL_ERR(("WPA2 IE parsing error"));
3758 goto exit;
3759 }
3760 err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
3761 if (err < 0) {
3762 WL_ERR(("SET INFRA error %d\n", err));
3763 goto exit;
3764 }
3765 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
3766 sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
3767 if (err < 0) {
3768 WL_ERR(("GO SSID setting error %d\n", err));
3769 goto exit;
3770 }
3771 if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
3772 WL_ERR(("GO Bring up error %d\n", err));
3773 goto exit;
3774 }
3775 }
3776 } else if (wl_get_drv_status(wl, AP_CREATING)) {
3777 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3778 ap = 1;
3779 /* find the SSID */
3780 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
3781 info->head_len - ie_offset,
3782 DOT11_MNG_SSID_ID)) != NULL) {
3783 memset(&ssid, 0, sizeof(wlc_ssid_t));
3784 memcpy(ssid.SSID, ssid_ie->data, ssid_ie->len);
3785 WL_DBG(("SSID is (%s) in Head \n", ssid.SSID));
3786 ssid.SSID_len = ssid_ie->len;
3787 wldev_iovar_setint(dev, "mpc", 0);
3788 wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
3789 wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
3790 if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
3791 WL_ERR(("setting AP mode failed %d \n", err));
3792 return err;
3793 }
3794 /* find the RSN_IE */
3795 if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
3796 DOT11_MNG_RSN_ID)) != NULL) {
3797 WL_DBG((" WPA2 IE is found\n"));
3798 }
3799 /* find the WPA_IE */
3800 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail,
3801 info->tail_len)) != NULL) {
3802 WL_DBG((" WPA IE is found\n"));
3803 }
3804 if ((wpa_ie != NULL || wpa2_ie != NULL)) {
3805 if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
3806 wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
3807 wl->ap_info->security_mode = false;
3808 return BCME_ERROR;
3809 }
3810 wl->ap_info->security_mode = true;
3811 if (wl->ap_info->rsn_ie) {
3812 kfree(wl->ap_info->rsn_ie);
3813 wl->ap_info->rsn_ie = NULL;
3814 }
3815 if (wl->ap_info->wpa_ie) {
3816 kfree(wl->ap_info->wpa_ie);
3817 wl->ap_info->wpa_ie = NULL;
3818 }
3819 if (wl->ap_info->wps_ie) {
3820 kfree(wl->ap_info->wps_ie);
3821 wl->ap_info->wps_ie = NULL;
3822 }
3823 if (wpa_ie != NULL) {
3824 /* WPAIE */
3825 wl->ap_info->rsn_ie = NULL;
3826 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3827 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3828 GFP_KERNEL);
3829 } else {
3830 /* RSNIE */
3831 wl->ap_info->wpa_ie = NULL;
3832 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3833 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3834 GFP_KERNEL);
3835 }
3836 } else
3837 wl->ap_info->security_mode = false;
3838 /* find the WPSIE */
3839 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail,
3840 info->tail_len)) != NULL) {
3841 wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
3842 /*
3843 * Should be compared with saved ie before saving it
3844 */
3845 wl_validate_wps_ie((char *) wps_ie, &pbc);
3846 memcpy(beacon_ie, wps_ie, wpsie_len);
3847 wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
3848 beacon_ie, wpsie_len);
3849 wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
3850 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3851 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3852 } else {
3853 WL_DBG(("No WPSIE in beacon \n"));
3854 }
3855 if (info->interval) {
3856 if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
3857 &info->interval, sizeof(s32), true)) < 0) {
3858 WL_ERR(("Beacon Interval Set Error, %d\n", err));
3859 return err;
3860 }
3861 }
3862 if (info->dtim_period) {
3863 if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
3864 &info->dtim_period, sizeof(s32), true)) < 0) {
3865 WL_ERR(("DTIM Interval Set Error, %d\n", err));
3866 return err;
3867 }
3868 }
3869 err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
3870 if (unlikely(err)) {
3871 WL_ERR(("WLC_UP error (%d)\n", err));
3872 return err;
3873 }
3874 memset(&join_params, 0, sizeof(join_params));
3875 /* join parameters starts with ssid */
3876 join_params_size = sizeof(join_params.ssid);
3877 memcpy(join_params.ssid.SSID, ssid.SSID, ssid.SSID_len);
3878 join_params.ssid.SSID_len = htod32(ssid.SSID_len);
3879 /* create softap */
3880 if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
3881 join_params_size, true)) == 0) {
3882 wl_clr_drv_status(wl, AP_CREATING);
3883 wl_set_drv_status(wl, AP_CREATED);
3884 }
3885 }
3886 } else if (wl_get_drv_status(wl, AP_CREATED)) {
3887 ap = 1;
3888 /* find the WPSIE */
3889 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
3890 wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
3891 /*
3892 * Should be compared with saved ie before saving it
3893 */
3894 wl_validate_wps_ie((char *) wps_ie, &pbc);
3895 memcpy(beacon_ie, wps_ie, wpsie_len);
3896 wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
3897 beacon_ie, wpsie_len);
3898 if (wl->ap_info->wps_ie &&
3899 memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
3900 WL_DBG((" WPS IE is changed\n"));
3901 kfree(wl->ap_info->wps_ie);
3902 wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
3903 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3904 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3905 } else if (wl->ap_info->wps_ie == NULL) {
3906 WL_DBG((" WPS IE is added\n"));
3907 wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
3908 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3909 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3910 }
3911 /* find the RSN_IE */
3912 if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
3913 DOT11_MNG_RSN_ID)) != NULL) {
3914 WL_DBG((" WPA2 IE is found\n"));
3915 }
3916 /* find the WPA_IE */
3917 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail,
3918 info->tail_len)) != NULL) {
3919 WL_DBG((" WPA IE is found\n"));
3920 }
3921 if ((wpa_ie != NULL || wpa2_ie != NULL)) {
3922 if (!wl->ap_info->security_mode) {
3923 /* change from open mode to security mode */
3924 update_bss = true;
3925 if (wpa_ie != NULL) {
3926 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3927 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3928 GFP_KERNEL);
3929 } else {
3930 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3931 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3932 GFP_KERNEL);
3933 }
3934 } else if (wl->ap_info->wpa_ie) {
3935 /* change from WPA mode to WPA2 mode */
3936 if (wpa2_ie != NULL) {
3937 update_bss = true;
3938 kfree(wl->ap_info->wpa_ie);
3939 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3940 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3941 GFP_KERNEL);
3942 wl->ap_info->wpa_ie = NULL;
3943 }
3944 else if (memcmp(wl->ap_info->wpa_ie,
3945 wpa_ie, wpa_ie->length +
3946 WPA_RSN_IE_TAG_FIXED_LEN)) {
3947 kfree(wl->ap_info->wpa_ie);
3948 update_bss = true;
3949 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3950 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3951 GFP_KERNEL);
3952 wl->ap_info->rsn_ie = NULL;
3953 }
3954 } else {
3955 /* change from WPA2 mode to WPA mode */
3956 if (wpa_ie != NULL) {
3957 update_bss = true;
3958 kfree(wl->ap_info->rsn_ie);
3959 wl->ap_info->rsn_ie = NULL;
3960 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3961 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3962 GFP_KERNEL);
3963 } else if (memcmp(wl->ap_info->rsn_ie,
3964 wpa2_ie, wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
3965 update_bss = true;
3966 kfree(wl->ap_info->rsn_ie);
3967 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3968 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3969 GFP_KERNEL);
3970 wl->ap_info->wpa_ie = NULL;
3971 }
3972 }
3973 if (update_bss) {
3974 wl->ap_info->security_mode = true;
3975 wl_cfgp2p_bss(dev, bssidx, 0);
3976 if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
3977 wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
3978 return BCME_ERROR;
3979 }
3980 wl_cfgp2p_bss(dev, bssidx, 1);
3981 }
3982 }
3983 } else {
3984 WL_ERR(("No WPSIE in beacon \n"));
3985 }
3986 }
3987exit:
3988 if (err)
3989 wldev_iovar_setint(dev, "mpc", 1);
3990 return err;
3991}
3992
3993static struct cfg80211_ops wl_cfg80211_ops = {
3994 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
3995 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
3996 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
3997 .scan = wl_cfg80211_scan,
3998 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
3999 .join_ibss = wl_cfg80211_join_ibss,
4000 .leave_ibss = wl_cfg80211_leave_ibss,
4001 .get_station = wl_cfg80211_get_station,
4002 .set_tx_power = wl_cfg80211_set_tx_power,
4003 .get_tx_power = wl_cfg80211_get_tx_power,
4004 .add_key = wl_cfg80211_add_key,
4005 .del_key = wl_cfg80211_del_key,
4006 .get_key = wl_cfg80211_get_key,
4007 .set_default_key = wl_cfg80211_config_default_key,
4008 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
4009 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
4010 .connect = wl_cfg80211_connect,
4011 .disconnect = wl_cfg80211_disconnect,
4012 .suspend = wl_cfg80211_suspend,
4013 .resume = wl_cfg80211_resume,
4014 .set_pmksa = wl_cfg80211_set_pmksa,
4015 .del_pmksa = wl_cfg80211_del_pmksa,
4016 .flush_pmksa = wl_cfg80211_flush_pmksa,
4017 .remain_on_channel = wl_cfg80211_remain_on_channel,
4018 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
4019 .mgmt_tx = wl_cfg80211_mgmt_tx,
4020 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
4021 .change_bss = wl_cfg80211_change_bss,
4022 .set_channel = wl_cfg80211_set_channel,
4023 .set_beacon = wl_cfg80211_add_set_beacon,
4024 .add_beacon = wl_cfg80211_add_set_beacon,
4025};
4026
4027static s32 wl_mode_to_nl80211_iftype(s32 mode)
4028{
4029 s32 err = 0;
4030
4031 switch (mode) {
4032 case WL_MODE_BSS:
4033 return NL80211_IFTYPE_STATION;
4034 case WL_MODE_IBSS:
4035 return NL80211_IFTYPE_ADHOC;
4036 case WL_MODE_AP:
4037 return NL80211_IFTYPE_AP;
4038 default:
4039 return NL80211_IFTYPE_UNSPECIFIED;
4040 }
4041
4042 return err;
4043}
4044
4045static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
4046{
4047 struct wireless_dev *wdev;
4048 s32 err = 0;
4049 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
4050 if (unlikely(!wdev)) {
4051 WL_ERR(("Could not allocate wireless device\n"));
4052 return ERR_PTR(-ENOMEM);
4053 }
4054 wdev->wiphy =
4055 wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
4056 if (unlikely(!wdev->wiphy)) {
4057 WL_ERR(("Couldn not allocate wiphy device\n"));
4058 err = -ENOMEM;
4059 goto wiphy_new_out;
4060 }
4061 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
4062 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
4063 /* Report how many SSIDs Driver can support per Scan request */
4064 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
4065 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4066 wdev->wiphy->interface_modes =
4067 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
4068 | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
4069
4070 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4071 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
4072 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4073 wdev->wiphy->cipher_suites = __wl_cipher_suites;
4074 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
4075 wdev->wiphy->max_remain_on_channel_duration = 5000;
4076 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
4077#ifndef WL_POWERSAVE_DISABLED
4078 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
4079#else
4080 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
4081#endif /* !WL_POWERSAVE_DISABLED */
4082 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
4083 WIPHY_FLAG_4ADDR_AP |
4084#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)
4085 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
4086#endif
4087 WIPHY_FLAG_4ADDR_STATION;
4088
4089 WL_DBG(("Registering custom regulatory)\n"));
4090 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
4091 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
4092 /* Now we can register wiphy with cfg80211 module */
4093 err = wiphy_register(wdev->wiphy);
4094 if (unlikely(err < 0)) {
4095 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
4096 goto wiphy_register_out;
4097 }
4098 return wdev;
4099
4100wiphy_register_out:
4101 wiphy_free(wdev->wiphy);
4102
4103wiphy_new_out:
4104 kfree(wdev);
4105
4106 return ERR_PTR(err);
4107}
4108
4109static void wl_free_wdev(struct wl_priv *wl)
4110{
4111 int i;
4112 struct wireless_dev *wdev = wl->wdev;
4113
4114 if (unlikely(!wdev)) {
4115 WL_ERR(("wdev is invalid\n"));
4116 return;
4117 }
4118
4119 for (i = 0; i < VWDEV_CNT; i++) {
4120 if ((wl->vwdev[i] != NULL)) {
4121 kfree(wl->vwdev[i]);
4122 wl->vwdev[i] = NULL;
4123 }
4124 }
4125 wiphy_unregister(wdev->wiphy);
4126 wdev->wiphy->dev.parent = NULL;
4127 wiphy_free(wdev->wiphy);
4128 kfree(wdev);
4129}
4130
4131static s32 wl_inform_bss(struct wl_priv *wl)
4132{
4133 struct wl_scan_results *bss_list;
4134 struct wl_bss_info *bi = NULL; /* must be initialized */
4135 s32 err = 0;
4136 s32 i;
4137
4138 bss_list = wl->bss_list;
4139 WL_DBG(("scanned AP count (%d)\n", bss_list->count));
4140 bi = next_bss(bss_list, bi);
4141 for_each_bss(bss_list, bi, i) {
4142 err = wl_inform_single_bss(wl, bi);
4143 if (unlikely(err))
4144 break;
4145 }
4146 return err;
4147}
4148
4149static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
4150{
4151 struct wiphy *wiphy = wiphy_from_scan(wl);
4152 struct ieee80211_mgmt *mgmt;
4153 struct ieee80211_channel *channel;
4154 struct ieee80211_supported_band *band;
4155 struct wl_cfg80211_bss_info *notif_bss_info;
4156 struct wl_scan_req *sr = wl_to_sr(wl);
4157 struct beacon_proberesp *beacon_proberesp;
4158 s32 mgmt_type;
4159 s32 signal;
4160 u32 freq;
4161 s32 err = 0;
4162
4163 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
4164 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
4165 return err;
4166 }
4167 notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt)
4168 - sizeof(u8) + WL_BSS_INFO_MAX, GFP_KERNEL);
4169 if (unlikely(!notif_bss_info)) {
4170 WL_ERR(("notif_bss_info alloc failed\n"));
4171 return -ENOMEM;
4172 }
4173 mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
4174 notif_bss_info->channel =
4175 bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec);
4176
4177 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
4178 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4179 else
4180 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4181 notif_bss_info->rssi = dtoh16(bi->RSSI);
4182 memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
4183 mgmt_type = wl->active_scan ?
4184 IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
4185 if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
4186 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
4187 }
4188 beacon_proberesp = wl->active_scan ?
4189 (struct beacon_proberesp *)&mgmt->u.probe_resp :
4190 (struct beacon_proberesp *)&mgmt->u.beacon;
4191 beacon_proberesp->timestamp = 0;
4192 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
4193 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
4194 wl_rst_ie(wl);
4195
4196 wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
4197 wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX -
4198 offsetof(struct wl_cfg80211_bss_info, frame_buf));
4199 notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
4200 u.beacon.variable) + wl_get_ielen(wl);
4201#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
4202 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
4203#else
4204 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
4205#endif
4206 channel = ieee80211_get_channel(wiphy, freq);
4207
4208 WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
4209 "mgmt_type %d frame_len %d\n", bi->SSID,
4210 notif_bss_info->rssi, notif_bss_info->channel,
4211 mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
4212 notif_bss_info->frame_len));
4213
4214 signal = notif_bss_info->rssi * 100;
4215
4216 if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
4217 le16_to_cpu(notif_bss_info->frame_len),
4218 signal, GFP_KERNEL))) {
4219 WL_ERR(("cfg80211_inform_bss_frame error\n"));
4220 kfree(notif_bss_info);
4221 return -EINVAL;
4222 }
4223 kfree(notif_bss_info);
4224
4225 return err;
4226}
4227
4228static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev)
4229{
4230 u32 event = ntoh32(e->event_type);
4231 u32 status = ntoh32(e->status);
4232 u16 flags = ntoh16(e->flags);
4233
4234 WL_DBG(("event %d, status %d\n", event, status));
4235 if (event == WLC_E_SET_SSID) {
4236 if (status == WLC_E_STATUS_SUCCESS) {
4237 if (!wl_is_ibssmode(wl, ndev))
4238 return true;
4239 }
4240 } else if (event == WLC_E_LINK) {
4241 if (flags & WLC_EVENT_MSG_LINK)
4242 return true;
4243 }
4244
4245 WL_DBG(("wl_is_linkup false\n"));
4246 return false;
4247}
4248
4249static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e)
4250{
4251 u32 event = ntoh32(e->event_type);
4252 u16 flags = ntoh16(e->flags);
4253
4254 if (event == WLC_E_DEAUTH_IND ||
4255 event == WLC_E_DISASSOC_IND ||
4256 event == WLC_E_DISASSOC ||
4257 event == WLC_E_DEAUTH) {
4258 return true;
4259 } else if (event == WLC_E_LINK) {
4260 if (!(flags & WLC_EVENT_MSG_LINK))
4261 return true;
4262 }
4263
4264 return false;
4265}
4266
4267static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
4268{
4269 u32 event = ntoh32(e->event_type);
4270 u32 status = ntoh32(e->status);
4271
4272 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
4273 return true;
4274 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
4275 return true;
4276
4277 return false;
4278}
4279
4280static s32
4281wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
4282 const wl_event_msg_t *e, void *data)
4283{
4284 bool act;
4285 bool isfree = false;
4286 s32 err = 0;
4287 s32 freq;
4288 s32 channel;
4289 u8 body[200];
4290 u32 event = ntoh32(e->event_type);
4291 u32 reason = ntoh32(e->reason);
4292 u32 len = ntoh32(e->datalen);
4293 u16 fc = 0;
4294 u8 *mgmt_frame;
4295 u8 bsscfgidx = e->bsscfgidx;
4296 struct ieee80211_supported_band *band;
4297 struct ether_addr da;
4298 struct ether_addr bssid;
4299 struct wiphy *wiphy = wl_to_wiphy(wl);
4300 channel_info_t ci;
4301
4302 memset(body, 0, sizeof(body));
4303 memset(&bssid, 0, ETHER_ADDR_LEN);
4304 WL_DBG(("Enter \n"));
4305
4306 if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
4307 memcpy(body, data, len);
4308 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
4309 NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
4310 memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
4311 err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
4312 switch (event) {
4313 case WLC_E_ASSOC_IND:
4314 fc = FC_ASSOC_REQ;
4315 break;
4316 case WLC_E_REASSOC_IND:
4317 fc = FC_REASSOC_REQ;
4318 break;
4319 case WLC_E_DISASSOC_IND:
4320 fc = FC_DISASSOC;
4321 break;
4322 case WLC_E_DEAUTH_IND:
4323 fc = FC_DISASSOC;
4324 break;
4325 case WLC_E_DEAUTH:
4326 fc = FC_DISASSOC;
4327 break;
4328 default:
4329 fc = 0;
4330 goto exit;
4331 }
4332 if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
4333 return err;
4334
4335 channel = dtoh32(ci.hw_channel);
4336 if (channel <= CH_MAX_2G_CHANNEL)
4337 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4338 else
4339 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4340
4341#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
4342 freq = ieee80211_channel_to_frequency(channel);
4343#else
4344 freq = ieee80211_channel_to_frequency(channel, band->band);
4345#endif
4346
4347 err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
4348 &mgmt_frame, &len, body);
4349 if (err < 0)
4350 goto exit;
4351 isfree = true;
4352
4353 if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
4354 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4355 } else if (event == WLC_E_DISASSOC_IND) {
4356 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4357 } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
4358 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4359 }
4360
4361 } else {
4362 WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
4363 ntoh32(e->event_type), ntoh32(e->status)));
4364 if (wl_is_linkup(wl, e, ndev)) {
4365 wl_link_up(wl);
4366 act = true;
4367 wl_update_prof(wl, e, &act, WL_PROF_ACT);
4368 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4369 if (wl_is_ibssmode(wl, ndev)) {
4370 printk("cfg80211_ibss_joined\n");
4371 cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
4372 GFP_KERNEL);
4373 WL_DBG(("joined in IBSS network\n"));
4374 } else {
4375 if (!wl_get_drv_status(wl, DISCONNECTING)) {
4376 printk("wl_bss_connect_done succeeded status=(0x%x)\n",
4377 (int)wl->status);
4378 wl_bss_connect_done(wl, ndev, e, data, true);
4379 WL_DBG(("joined in BSS network \"%s\"\n",
4380 ((struct wlc_ssid *)
4381 wl_read_prof(wl, WL_PROF_SSID))->SSID));
4382 }
4383 }
4384
4385 } else if (wl_is_linkdown(wl, e)) {
4386 if (wl->scan_request) {
4387 del_timer_sync(&wl->scan_timeout);
4388 if (wl->escan_on) {
4389 wl_notify_escan_complete(wl, true);
4390 } else
4391 wl_iscan_aborted(wl);
4392 }
4393 if (wl_get_drv_status(wl, CONNECTED)) {
4394 scb_val_t scbval;
4395 u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4396 printk("link down, call cfg80211_disconnected\n");
4397 wl_clr_drv_status(wl, CONNECTED);
4398 /* To make sure disconnect, explictly send dissassoc
4399 * for BSSID 00:00:00:00:00:00 issue
4400 */
4401 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
4402
4403 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4404 scbval.val = htod32(scbval.val);
4405 wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
4406 sizeof(scb_val_t), true);
4407 cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
4408 wl_link_down(wl);
4409 wl_init_prof(wl);
4410 } else if (wl_get_drv_status(wl, CONNECTING)) {
4411 printk("link down, during connecting\n");
4412 wl_bss_connect_done(wl, ndev, e, data, false);
4413 }
4414 wl_clr_drv_status(wl, DISCONNECTING);
4415
4416 } else if (wl_is_nonetwork(wl, e)) {
4417 printk("connect failed event=%d e->status 0x%x\n",
4418 event, (int)ntoh32(e->status));
4419 /* Clean up any pending scan request */
4420 if (wl->scan_request) {
4421 del_timer_sync(&wl->scan_timeout);
4422 if (wl->escan_on) {
4423 wl_notify_escan_complete(wl, true);
4424 } else
4425 wl_iscan_aborted(wl);
4426 }
4427 if (wl_get_drv_status(wl, CONNECTING))
4428 wl_bss_connect_done(wl, ndev, e, data, false);
4429 } else {
4430 printk("%s nothing\n", __FUNCTION__);
4431 }
4432 }
4433exit:
4434 if (isfree)
4435 kfree(mgmt_frame);
4436 return err;
4437}
4438
4439static s32
4440wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
4441 const wl_event_msg_t *e, void *data)
4442{
4443 bool act;
4444 s32 err = 0;
4445 u32 event = be32_to_cpu(e->event_type);
4446 u32 status = be32_to_cpu(e->status);
4447 WL_DBG(("Enter \n"));
4448 if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
4449 if (wl_get_drv_status(wl, CONNECTED))
4450 wl_bss_roaming_done(wl, ndev, e, data);
4451 else
4452 wl_bss_connect_done(wl, ndev, e, data, true);
4453 act = true;
4454 wl_update_prof(wl, e, &act, WL_PROF_ACT);
4455 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4456 }
4457 return err;
4458}
4459
4460static __used s32
4461wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
4462{
4463 struct wl_priv *wl = wlcfg_drv_priv;
4464 u32 buflen;
4465
4466 buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
4467 BUG_ON(unlikely(!buflen));
4468
4469 return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
4470}
4471
4472static s32
4473wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
4474 s32 buf_len)
4475{
4476 struct wl_priv *wl = wlcfg_drv_priv;
4477 u32 len;
4478 s32 err = 0;
4479
4480 len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
4481 BUG_ON(unlikely(!len));
4482 err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
4483 WL_IOCTL_LEN_MAX, false);
4484 if (unlikely(err)) {
4485 WL_ERR(("error (%d)\n", err));
4486 return err;
4487 }
4488 memcpy(buf, wl->ioctl_buf, buf_len);
4489
4490 return err;
4491}
4492
4493static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
4494{
4495 wl_assoc_info_t assoc_info;
4496 struct wl_connect_info *conn_info = wl_to_conn(wl);
4497 s32 err = 0;
4498
4499 WL_DBG(("Enter \n"));
4500 err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
4501 WL_ASSOC_INFO_MAX);
4502 if (unlikely(err)) {
4503 WL_ERR(("could not get assoc info (%d)\n", err));
4504 return err;
4505 }
4506 memcpy(&assoc_info, wl->extra_buf, sizeof(wl_assoc_info_t));
4507 assoc_info.req_len = htod32(assoc_info.req_len);
4508 assoc_info.resp_len = htod32(assoc_info.resp_len);
4509 assoc_info.flags = htod32(assoc_info.flags);
4510 if (conn_info->req_ie_len) {
4511 conn_info->req_ie_len = 0;
4512 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
4513 }
4514 if (conn_info->resp_ie_len) {
4515 conn_info->resp_ie_len = 0;
4516 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
4517 }
4518 if (assoc_info.req_len) {
4519 err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
4520 WL_ASSOC_INFO_MAX);
4521 if (unlikely(err)) {
4522 WL_ERR(("could not get assoc req (%d)\n", err));
4523 return err;
4524 }
4525 conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
4526 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
4527 conn_info->req_ie_len -= ETHER_ADDR_LEN;
4528 }
4529 if (conn_info->req_ie_len <= MAX_REQ_LINE)
4530 memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len);
4531 else {
4532 WL_ERR(("%s IE size %d above max %d size \n",
4533 __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE));
4534 return err;
4535 }
4536 } else {
4537 conn_info->req_ie_len = 0;
4538 }
4539 if (assoc_info.resp_len) {
4540 err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
4541 WL_ASSOC_INFO_MAX);
4542 if (unlikely(err)) {
4543 WL_ERR(("could not get assoc resp (%d)\n", err));
4544 return err;
4545 }
4546 conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
4547 if (conn_info->resp_ie_len <= MAX_REQ_LINE)
4548 memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len);
4549 else {
4550 WL_ERR(("%s IE size %d above max %d size \n",
4551 __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE));
4552 return err;
4553 }
4554 } else {
4555 conn_info->resp_ie_len = 0;
4556 }
4557 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
4558 conn_info->resp_ie_len));
4559
4560 return err;
4561}
4562
4563static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
4564 size_t *join_params_size)
4565{
4566 chanspec_t chanspec = 0;
4567
4568 if (ch != 0) {
4569 join_params->params.chanspec_num = 1;
4570 join_params->params.chanspec_list[0] = ch;
4571
4572 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
4573 chanspec |= WL_CHANSPEC_BAND_2G;
4574 else
4575 chanspec |= WL_CHANSPEC_BAND_5G;
4576
4577 chanspec |= WL_CHANSPEC_BW_20;
4578 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
4579
4580 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
4581 join_params->params.chanspec_num * sizeof(chanspec_t);
4582
4583 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
4584 join_params->params.chanspec_list[0] |= chanspec;
4585 join_params->params.chanspec_list[0] =
4586 htodchanspec(join_params->params.chanspec_list[0]);
4587
4588 join_params->params.chanspec_num =
4589 htod32(join_params->params.chanspec_num);
4590
4591 WL_DBG(("%s join_params->params.chanspec_list[0]= %X\n",
4592 __FUNCTION__, join_params->params.chanspec_list[0]));
4593
4594 }
4595}
4596
4597static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
4598{
4599 struct cfg80211_bss *bss;
4600 struct wl_bss_info *bi;
4601 struct wlc_ssid *ssid;
4602 struct bcm_tlv *tim;
4603 u16 beacon_interval;
4604 u8 dtim_period;
4605 size_t ie_len;
4606 u8 *ie;
4607 u8 *curbssid;
4608 s32 err = 0;
4609 struct wiphy *wiphy;
4610 wiphy = wl_to_wiphy(wl);
4611
4612 if (wl_is_ibssmode(wl, ndev))
4613 return err;
4614
4615 ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
4616 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4617 bss = cfg80211_get_bss(wiphy, NULL, curbssid,
4618 ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
4619 WLAN_CAPABILITY_ESS);
4620
4621 mutex_lock(&wl->usr_sync);
4622 if (unlikely(!bss)) {
4623 WL_DBG(("Could not find the AP\n"));
4624 *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
4625 err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
4626 wl->extra_buf, WL_EXTRA_BUF_MAX, false);
4627 if (unlikely(err)) {
4628 WL_ERR(("Could not get bss info %d\n", err));
4629 goto update_bss_info_out;
4630 }
4631 bi = (struct wl_bss_info *)(wl->extra_buf + 4);
4632 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
4633 err = -EIO;
4634 goto update_bss_info_out;
4635 }
4636 err = wl_inform_single_bss(wl, bi);
4637 if (unlikely(err))
4638 goto update_bss_info_out;
4639
4640 ie = ((u8 *)bi) + bi->ie_offset;
4641 ie_len = bi->ie_length;
4642 beacon_interval = cpu_to_le16(bi->beacon_period);
4643 } else {
4644 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
4645 ie = bss->information_elements;
4646 ie_len = bss->len_information_elements;
4647 beacon_interval = bss->beacon_interval;
4648 cfg80211_put_bss(bss);
4649 }
4650
4651 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
4652 if (tim) {
4653 dtim_period = tim->data[1];
4654 } else {
4655 /*
4656 * active scan was done so we could not get dtim
4657 * information out of probe response.
4658 * so we speficially query dtim information to dongle.
4659 */
4660 err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
4661 &dtim_period, sizeof(dtim_period), false);
4662 if (unlikely(err)) {
4663 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
4664 goto update_bss_info_out;
4665 }
4666 }
4667
4668 wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
4669 wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
4670
4671update_bss_info_out:
4672 mutex_unlock(&wl->usr_sync);
4673 return err;
4674}
4675
4676static s32
4677wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
4678 const wl_event_msg_t *e, void *data)
4679{
4680 struct wl_connect_info *conn_info = wl_to_conn(wl);
4681 s32 err = 0;
4682 u8 *curbssid;
4683
4684 wl_get_assoc_ies(wl, ndev);
4685 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4686 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4687 wl_update_bss_info(wl, ndev);
4688 wl_update_pmklist(ndev, wl->pmk_list, err);
4689 cfg80211_roamed(ndev,
4690#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
4691 NULL,
4692#endif
4693 curbssid,
4694 conn_info->req_ie, conn_info->req_ie_len,
4695 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4696 WL_DBG(("Report roaming result\n"));
4697
4698 wl_set_drv_status(wl, CONNECTED);
4699
4700 return err;
4701}
4702
4703static s32
4704wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
4705 const wl_event_msg_t *e, void *data, bool completed)
4706{
4707 struct wl_connect_info *conn_info = wl_to_conn(wl);
4708 s32 err = 0;
4709 u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4710 WL_DBG((" enter\n"));
4711 if (wl->scan_request) {
4712 wl_cfg80211_scan_abort(wl, ndev);
4713 }
4714 if (wl_get_drv_status(wl, CONNECTING)) {
4715 wl_clr_drv_status(wl, CONNECTING);
4716 if (completed) {
4717 wl_get_assoc_ies(wl, ndev);
4718 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4719 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4720 wl_update_bss_info(wl, ndev);
4721 wl_update_pmklist(ndev, wl->pmk_list, err);
4722 wl_set_drv_status(wl, CONNECTED);
4723 }
4724 cfg80211_connect_result(ndev,
4725 curbssid,
4726 conn_info->req_ie,
4727 conn_info->req_ie_len,
4728 conn_info->resp_ie,
4729 conn_info->resp_ie_len,
4730 completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
4731 GFP_KERNEL);
4732 if (completed)
4733 WL_INFO(("Report connect result - connection succeeded\n"));
4734 else
4735 WL_ERR(("Report connect result - connection failed\n"));
4736 }
4737 return err;
4738}
4739
4740static s32
4741wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
4742 const wl_event_msg_t *e, void *data)
4743{
4744 u16 flags = ntoh16(e->flags);
4745 enum nl80211_key_type key_type;
4746
4747 mutex_lock(&wl->usr_sync);
4748 if (flags & WLC_EVENT_MSG_GROUP)
4749 key_type = NL80211_KEYTYPE_GROUP;
4750 else
4751 key_type = NL80211_KEYTYPE_PAIRWISE;
4752
4753 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
4754 NULL, GFP_KERNEL);
4755 mutex_unlock(&wl->usr_sync);
4756
4757 return 0;
4758}
4759
4760static s32
4761wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
4762 const wl_event_msg_t *e, void *data)
4763{
4764 struct channel_info channel_inform;
4765 struct wl_scan_results *bss_list;
4766 u32 len = WL_SCAN_BUF_MAX;
4767 s32 err = 0;
4768 unsigned long flags;
4769
4770 WL_DBG(("Enter \n"));
4771 if (wl->iscan_on && wl->iscan_kickstart)
4772 return wl_wakeup_iscan(wl_to_iscan(wl));
4773
4774 mutex_lock(&wl->usr_sync);
4775 wl_clr_drv_status(wl, SCANNING);
4776 err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
4777 sizeof(channel_inform), false);
4778 if (unlikely(err)) {
4779 WL_ERR(("scan busy (%d)\n", err));
4780 goto scan_done_out;
4781 }
4782 channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
4783 if (unlikely(channel_inform.scan_channel)) {
4784
4785 WL_DBG(("channel_inform.scan_channel (%d)\n",
4786 channel_inform.scan_channel));
4787 }
4788 wl->bss_list = wl->scan_results;
4789 bss_list = wl->bss_list;
4790 memset(bss_list, 0, len);
4791 bss_list->buflen = htod32(len);
4792 err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
4793 if (unlikely(err)) {
4794 WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
4795 err = -EINVAL;
4796 goto scan_done_out;
4797 }
4798 bss_list->buflen = dtoh32(bss_list->buflen);
4799 bss_list->version = dtoh32(bss_list->version);
4800 bss_list->count = dtoh32(bss_list->count);
4801
4802 err = wl_inform_bss(wl);
4803
4804scan_done_out:
4805 del_timer_sync(&wl->scan_timeout);
4806 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
4807 if (wl->scan_request) {
4808 WL_DBG(("cfg80211_scan_done\n"));
4809 cfg80211_scan_done(wl->scan_request, false);
4810 wl->scan_request = NULL;
4811 }
4812 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
4813 mutex_unlock(&wl->usr_sync);
4814 return err;
4815}
4816static s32
4817wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
4818 const struct ether_addr *sa, const struct ether_addr *bssid,
4819 u8 **pheader, u32 *body_len, u8 *pbody)
4820{
4821 struct dot11_management_header *hdr;
4822 u32 totlen = 0;
4823 s32 err = 0;
4824 u8 *offset;
4825 u32 prebody_len = *body_len;
4826 switch (fc) {
4827 case FC_ASSOC_REQ:
4828 /* capability , listen interval */
4829 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
4830 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
4831 break;
4832
4833 case FC_REASSOC_REQ:
4834 /* capability, listen inteval, ap address */
4835 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
4836 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
4837 break;
4838 }
4839 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
4840 *pheader = kzalloc(totlen, GFP_KERNEL);
4841 if (*pheader == NULL) {
4842 WL_ERR(("memory alloc failed \n"));
4843 return -ENOMEM;
4844 }
4845 hdr = (struct dot11_management_header *) (*pheader);
4846 hdr->fc = htol16(fc);
4847 hdr->durid = 0;
4848 hdr->seq = 0;
4849 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
4850 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
4851 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
4852 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
4853 bcopy((const char*)pbody, offset, prebody_len);
4854 *body_len = totlen;
4855 return err;
4856}
4857static s32
4858wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
4859 const wl_event_msg_t *e, void *data)
4860{
4861 struct ieee80211_supported_band *band;
4862 struct wiphy *wiphy = wl_to_wiphy(wl);
4863 struct ether_addr da;
4864 struct ether_addr bssid;
4865 bool isfree = false;
4866 s32 err = 0;
4867 s32 freq;
4868 wifi_p2p_pub_act_frame_t *act_frm;
4869 wl_event_rx_frame_data_t *rxframe =
4870 (wl_event_rx_frame_data_t*)data;
4871 u32 event = ntoh32(e->event_type);
4872 u8 *mgmt_frame;
4873 u8 bsscfgidx = e->bsscfgidx;
4874 u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
4875 u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
4876
4877 memset(&bssid, 0, ETHER_ADDR_LEN);
4878 if (channel <= CH_MAX_2G_CHANNEL)
4879 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4880 else
4881 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4882
4883#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
4884 freq = ieee80211_channel_to_frequency(channel);
4885#else
4886 freq = ieee80211_channel_to_frequency(channel, band->band);
4887#endif
4888 if (event == WLC_E_ACTION_FRAME_RX) {
4889 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
4890 NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
4891
4892 wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
4893 memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
4894 err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
4895 &mgmt_frame, &mgmt_frame_len,
4896 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
4897 if (err < 0) {
4898 WL_ERR(("%s: Error in receiving action frame len %d channel %d freq %d\n",
4899 __func__, mgmt_frame_len, channel, freq));
4900 goto exit;
4901 }
4902 isfree = true;
4903 act_frm =
4904 (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
4905 /*
4906 * After complete GO Negotiation, roll back to mpc mode
4907 */
4908 if (act_frm->subtype == P2P_PAF_GON_CONF) {
4909 wldev_iovar_setint(ndev, "mpc", 1);
4910 }
4911 } else {
4912 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
4913 }
4914
4915 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
4916
4917 WL_DBG(("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__,
4918 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
4919
4920 if (isfree)
4921 kfree(mgmt_frame);
4922exit:
4923 return 0;
4924}
4925
4926static void wl_init_conf(struct wl_conf *conf)
4927{
4928 s32 i = 0;
4929 WL_DBG(("Enter \n"));
4930 for (i = 0; i <= VWDEV_CNT; i++) {
4931 conf->mode[i].type = -1;
4932 conf->mode[i].ndev = NULL;
4933 }
4934 conf->frag_threshold = (u32)-1;
4935 conf->rts_threshold = (u32)-1;
4936 conf->retry_short = (u32)-1;
4937 conf->retry_long = (u32)-1;
4938 conf->tx_power = -1;
4939}
4940
4941static void wl_init_prof(struct wl_priv *wl)
4942{
4943 unsigned long flags;
4944
4945 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
4946 memset(wl->profile, 0, sizeof(struct wl_profile));
4947 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
4948}
4949
4950static void wl_init_event_handler(struct wl_priv *wl)
4951{
4952 memset(wl->evt_handler, 0, sizeof(wl->evt_handler));
4953
4954 wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
4955 wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
4956 wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
4957 wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
4958 wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
4959 wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
4960 wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
4961 wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
4962 wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
4963 wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
4964 wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
4965 wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
4966 wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
4967 wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
4968 wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
4969 wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
4970
4971}
4972
4973static s32 wl_init_priv_mem(struct wl_priv *wl)
4974{
4975 WL_DBG(("Enter \n"));
4976 wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
4977 if (unlikely(!wl->scan_results)) {
4978 WL_ERR(("Scan results alloc failed\n"));
4979 goto init_priv_mem_out;
4980 }
4981 wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL);
4982 if (unlikely(!wl->conf)) {
4983 WL_ERR(("wl_conf alloc failed\n"));
4984 goto init_priv_mem_out;
4985 }
4986 wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
4987 if (unlikely(!wl->profile)) {
4988 WL_ERR(("wl_profile alloc failed\n"));
4989 goto init_priv_mem_out;
4990 }
4991 wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4992 if (unlikely(!wl->bss_info)) {
4993 WL_ERR(("Bss information alloc failed\n"));
4994 goto init_priv_mem_out;
4995 }
4996 wl->scan_req_int =
4997 (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
4998 if (unlikely(!wl->scan_req_int)) {
4999 WL_ERR(("Scan req alloc failed\n"));
5000 goto init_priv_mem_out;
5001 }
5002 wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
5003 if (unlikely(!wl->ioctl_buf)) {
5004 WL_ERR(("Ioctl buf alloc failed\n"));
5005 goto init_priv_mem_out;
5006 }
5007 wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
5008 if (unlikely(!wl->escan_ioctl_buf)) {
5009 WL_ERR(("Ioctl buf alloc failed\n"));
5010 goto init_priv_mem_out;
5011 }
5012 wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5013 if (unlikely(!wl->extra_buf)) {
5014 WL_ERR(("Extra buf alloc failed\n"));
5015 goto init_priv_mem_out;
5016 }
5017 wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
5018 if (unlikely(!wl->iscan)) {
5019 WL_ERR(("Iscan buf alloc failed\n"));
5020 goto init_priv_mem_out;
5021 }
5022 wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
5023 if (unlikely(!wl->fw)) {
5024 WL_ERR(("fw object alloc failed\n"));
5025 goto init_priv_mem_out;
5026 }
5027 wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
5028 if (unlikely(!wl->pmk_list)) {
5029 WL_ERR(("pmk list alloc failed\n"));
5030 goto init_priv_mem_out;
5031 }
5032 wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL);
5033 if (unlikely(!wl->sta_info)) {
5034 WL_ERR(("sta info alloc failed\n"));
5035 goto init_priv_mem_out;
5036 }
5037 return 0;
5038
5039init_priv_mem_out:
5040 wl_deinit_priv_mem(wl);
5041
5042 return -ENOMEM;
5043}
5044
5045static void wl_deinit_priv_mem(struct wl_priv *wl)
5046{
5047 kfree(wl->scan_results);
5048 wl->scan_results = NULL;
5049 kfree(wl->bss_info);
5050 wl->bss_info = NULL;
5051 kfree(wl->conf);
5052 wl->conf = NULL;
5053 kfree(wl->profile);
5054 wl->profile = NULL;
5055 kfree(wl->scan_req_int);
5056 wl->scan_req_int = NULL;
5057 kfree(wl->ioctl_buf);
5058 wl->ioctl_buf = NULL;
5059 kfree(wl->escan_ioctl_buf);
5060 wl->escan_ioctl_buf = NULL;
5061 kfree(wl->extra_buf);
5062 wl->extra_buf = NULL;
5063 kfree(wl->iscan);
5064 wl->iscan = NULL;
5065 kfree(wl->fw);
5066 wl->fw = NULL;
5067 kfree(wl->pmk_list);
5068 wl->pmk_list = NULL;
5069 kfree(wl->sta_info);
5070 wl->sta_info = NULL;
5071 if (wl->ap_info) {
5072 kfree(wl->ap_info->wpa_ie);
5073 kfree(wl->ap_info->rsn_ie);
5074 kfree(wl->ap_info->wps_ie);
5075 kfree(wl->ap_info);
5076 wl->ap_info = NULL;
5077 }
5078}
5079
5080static s32 wl_create_event_handler(struct wl_priv *wl)
5081{
5082 int ret = 0;
5083 WL_DBG(("Enter \n"));
5084
5085 wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
5086 PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
5087 if (wl->event_tsk.thr_pid < 0)
5088 ret = -ENOMEM;
5089 return ret;
5090}
5091
5092static void wl_destroy_event_handler(struct wl_priv *wl)
5093{
5094 if (wl->event_tsk.thr_pid >= 0)
5095 PROC_STOP(&wl->event_tsk);
5096}
5097
5098static void wl_term_iscan(struct wl_priv *wl)
5099{
5100 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
5101 WL_TRACE(("In\n"));
5102 if (wl->iscan_on && iscan->tsk) {
5103 iscan->state = WL_ISCAN_STATE_IDLE;
5104 WL_INFO(("SIGTERM\n"));
5105 send_sig(SIGTERM, iscan->tsk, 1);
5106 WL_DBG(("kthread_stop\n"));
5107 kthread_stop(iscan->tsk);
5108 iscan->tsk = NULL;
5109 }
5110}
5111
5112static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
5113{
5114 struct wl_priv *wl = iscan_to_wl(iscan);
5115 unsigned long flags;
5116
5117 WL_DBG(("Enter \n"));
5118 if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
5119 wl_clr_drv_status(wl, SCANNING);
5120 WL_ERR(("Scan complete while device not scanning\n"));
5121 return;
5122 }
5123 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
5124 wl_clr_drv_status(wl, SCANNING);
5125 if (likely(wl->scan_request)) {
5126 cfg80211_scan_done(wl->scan_request, aborted);
5127 wl->scan_request = NULL;
5128 }
5129 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
5130 wl->iscan_kickstart = false;
5131}
5132
5133static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan)
5134{
5135 if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) {
5136 WL_DBG(("wake up iscan\n"));
5137 up(&iscan->sync);
5138 return 0;
5139 }
5140
5141 return -EIO;
5142}
5143
5144static s32
5145wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
5146 struct wl_scan_results **bss_list)
5147{
5148 struct wl_iscan_results list;
5149 struct wl_scan_results *results;
5150 struct wl_iscan_results *list_buf;
5151 s32 err = 0;
5152
5153 WL_DBG(("Enter \n"));
5154 memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
5155 list_buf = (struct wl_iscan_results *)iscan->scan_buf;
5156 results = &list_buf->results;
5157 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
5158 results->version = 0;
5159 results->count = 0;
5160
5161 memset(&list, 0, sizeof(list));
5162 list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
5163 err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list,
5164 WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
5165 WL_ISCAN_BUF_MAX);
5166 if (unlikely(err)) {
5167 WL_ERR(("error (%d)\n", err));
5168 return err;
5169 }
5170 results->buflen = dtoh32(results->buflen);
5171 results->version = dtoh32(results->version);
5172 results->count = dtoh32(results->count);
5173 WL_DBG(("results->count = %d\n", results->count));
5174 WL_DBG(("results->buflen = %d\n", results->buflen));
5175 *status = dtoh32(list_buf->status);
5176 *bss_list = results;
5177
5178 return err;
5179}
5180
5181static s32 wl_iscan_done(struct wl_priv *wl)
5182{
5183 struct wl_iscan_ctrl *iscan = wl->iscan;
5184 s32 err = 0;
5185
5186 iscan->state = WL_ISCAN_STATE_IDLE;
5187 mutex_lock(&wl->usr_sync);
5188 wl_inform_bss(wl);
5189 wl_notify_iscan_complete(iscan, false);
5190 mutex_unlock(&wl->usr_sync);
5191
5192 return err;
5193}
5194
5195static s32 wl_iscan_pending(struct wl_priv *wl)
5196{
5197 struct wl_iscan_ctrl *iscan = wl->iscan;
5198 s32 err = 0;
5199
5200 /* Reschedule the timer */
5201 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
5202 iscan->timer_on = 1;
5203
5204 return err;
5205}
5206
5207static s32 wl_iscan_inprogress(struct wl_priv *wl)
5208{
5209 struct wl_iscan_ctrl *iscan = wl->iscan;
5210 s32 err = 0;
5211
5212 mutex_lock(&wl->usr_sync);
5213 wl_inform_bss(wl);
5214 wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
5215 mutex_unlock(&wl->usr_sync);
5216 /* Reschedule the timer */
5217 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
5218 iscan->timer_on = 1;
5219
5220 return err;
5221}
5222
5223static s32 wl_iscan_aborted(struct wl_priv *wl)
5224{
5225 struct wl_iscan_ctrl *iscan = wl->iscan;
5226 s32 err = 0;
5227
5228 iscan->state = WL_ISCAN_STATE_IDLE;
5229 mutex_lock(&wl->usr_sync);
5230 wl_notify_iscan_complete(iscan, true);
5231 mutex_unlock(&wl->usr_sync);
5232
5233 return err;
5234}
5235
5236static s32 wl_iscan_thread(void *data)
5237{
5238 struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
5239 struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
5240 struct wl_priv *wl = iscan_to_wl(iscan);
5241 u32 status;
5242 int err = 0;
5243
5244 sched_setscheduler(current, SCHED_FIFO, &param);
5245 allow_signal(SIGTERM);
5246 status = WL_SCAN_RESULTS_PARTIAL;
5247 while (likely(!down_interruptible(&iscan->sync))) {
5248 if (kthread_should_stop())
5249 break;
5250 if (iscan->timer_on) {
5251 del_timer_sync(&iscan->timer);
5252 iscan->timer_on = 0;
5253 }
5254 mutex_lock(&wl->usr_sync);
5255 err = wl_get_iscan_results(iscan, &status, &wl->bss_list);
5256 if (unlikely(err)) {
5257 status = WL_SCAN_RESULTS_ABORTED;
5258 WL_ERR(("Abort iscan\n"));
5259 }
5260 mutex_unlock(&wl->usr_sync);
5261 iscan->iscan_handler[status] (wl);
5262 }
5263 if (iscan->timer_on) {
5264 del_timer_sync(&iscan->timer);
5265 iscan->timer_on = 0;
5266 }
5267 WL_DBG(("%s was terminated\n", __func__));
5268
5269 return 0;
5270}
5271
5272static void wl_scan_timeout(unsigned long data)
5273{
5274 struct wl_priv *wl = (struct wl_priv *)data;
5275
5276 if (wl->scan_request) {
5277 WL_ERR(("timer expired\n"));
5278 if (wl->escan_on)
5279 wl_notify_escan_complete(wl, true);
5280 else
5281 wl_notify_iscan_complete(wl_to_iscan(wl), true);
5282 }
5283}
5284
5285static void wl_iscan_timer(unsigned long data)
5286{
5287 struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
5288
5289 if (iscan) {
5290 iscan->timer_on = 0;
5291 WL_DBG(("timer expired\n"));
5292 wl_wakeup_iscan(iscan);
5293 }
5294}
5295
5296static s32 wl_invoke_iscan(struct wl_priv *wl)
5297{
5298 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
5299 int err = 0;
5300
5301 if (wl->iscan_on && !iscan->tsk) {
5302 iscan->state = WL_ISCAN_STATE_IDLE;
5303 sema_init(&iscan->sync, 0);
5304 iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
5305 if (IS_ERR(iscan->tsk)) {
5306 WL_ERR(("Could not create iscan thread\n"));
5307 iscan->tsk = NULL;
5308 return -ENOMEM;
5309 }
5310 }
5311
5312 return err;
5313}
5314
5315static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan)
5316{
5317 memset(iscan->iscan_handler, 0, sizeof(iscan->iscan_handler));
5318 iscan->iscan_handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done;
5319 iscan->iscan_handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress;
5320 iscan->iscan_handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending;
5321 iscan->iscan_handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted;
5322 iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
5323}
5324
5325static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
5326{
5327 unsigned long flags;
5328
5329 WL_DBG(("Enter \n"));
5330 wl_clr_drv_status(wl, SCANNING);
5331 if (wl->p2p_supported && p2p_on(wl))
5332 wl_clr_p2p_status(wl, SCANNING);
5333
5334 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
5335 if (likely(wl->scan_request)) {
5336 cfg80211_scan_done(wl->scan_request, aborted);
5337 wl->scan_request = NULL;
5338 }
5339 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
5340}
5341
5342static s32 wl_escan_handler(struct wl_priv *wl,
5343 struct net_device *ndev,
5344 const wl_event_msg_t *e, void *data)
5345{
5346 s32 err = BCME_OK;
5347 s32 status = ntoh32(e->status);
5348 wl_bss_info_t *bi;
5349 wl_escan_result_t *escan_result;
5350 wl_bss_info_t *bss = NULL;
5351 wl_scan_results_t *list;
5352 u32 bi_length;
5353 u32 i;
5354 WL_DBG((" enter event type : %d, status : %d \n",
5355 ntoh32(e->event_type), ntoh32(e->status)));
5356 if (!wl->escan_on &&
5357 !wl_get_drv_status(wl, SCANNING)) {
5358 WL_ERR(("escan is not ready \n"));
5359 return err;
5360 }
5361
5362 if (status == WLC_E_STATUS_PARTIAL) {
5363 WL_INFO(("WLC_E_STATUS_PARTIAL \n"));
5364 escan_result = (wl_escan_result_t *) data;
5365 if (!escan_result) {
5366 WL_ERR(("Invalid escan result (NULL pointer)\n"));
5367 goto exit;
5368 }
5369 if (dtoh16(escan_result->bss_count) != 1) {
5370 WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
5371 goto exit;
5372 }
5373 bi = escan_result->bss_info;
5374 if (!bi) {
5375 WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
5376 goto exit;
5377 }
5378 bi_length = dtoh32(bi->length);
5379 if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
5380 WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
5381 goto exit;
5382 }
5383 list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5384 if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
5385 WL_ERR(("Buffer is too small: ignoring\n"));
5386 goto exit;
5387 }
5388#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
5389 for (i = 0; i < list->count; i++) {
5390 bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
5391 : list->bss_info;
5392
5393 if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
5394 CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
5395 bi->SSID_len == bss->SSID_len &&
5396 !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
5397 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
5398 (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
5399 /* preserve max RSSI if the measurements are
5400 * both on-channel or both off-channel
5401 */
5402 bss->RSSI = MAX(bss->RSSI, bi->RSSI);
5403 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
5404 (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
5405 /* preserve the on-channel rssi measurement
5406 * if the new measurement is off channel
5407 */
5408 bss->RSSI = bi->RSSI;
5409 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
5410 }
5411
5412 goto exit;
5413 }
5414 }
5415 memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
5416 list->version = dtoh32(bi->version);
5417 list->buflen += bi_length;
5418 list->count++;
5419
5420 }
5421 else if (status == WLC_E_STATUS_SUCCESS) {
5422 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5423 if (likely(wl->scan_request)) {
5424 mutex_lock(&wl->usr_sync);
5425 del_timer_sync(&wl->scan_timeout);
5426 WL_INFO(("ESCAN COMPLETED\n"));
5427 wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5428 wl_inform_bss(wl);
5429 wl_notify_escan_complete(wl, false);
5430 mutex_unlock(&wl->usr_sync);
5431 }
5432 }
5433 else if (status == WLC_E_STATUS_ABORT) {
5434 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5435 if (likely(wl->scan_request)) {
5436 mutex_lock(&wl->usr_sync);
5437 del_timer_sync(&wl->scan_timeout);
5438 WL_INFO(("ESCAN ABORTED\n"));
5439 wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5440 wl_inform_bss(wl);
5441 wl_notify_escan_complete(wl, true);
5442 mutex_unlock(&wl->usr_sync);
5443 }
5444 }
5445 else {
5446 WL_ERR(("unexpected Escan Event %d : abort\n", status));
5447 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5448 if (likely(wl->scan_request)) {
5449 mutex_lock(&wl->usr_sync);
5450 del_timer_sync(&wl->scan_timeout);
5451 wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5452 wl_inform_bss(wl);
5453 wl_notify_escan_complete(wl, true);
5454 mutex_unlock(&wl->usr_sync);
5455 }
5456 }
5457exit:
5458 return err;
5459}
5460
5461static s32 wl_init_scan(struct wl_priv *wl)
5462{
5463 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
5464 int err = 0;
5465
5466 if (wl->iscan_on) {
5467 iscan->dev = wl_to_prmry_ndev(wl);
5468 iscan->state = WL_ISCAN_STATE_IDLE;
5469 wl_init_iscan_handler(iscan);
5470 iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
5471 init_timer(&iscan->timer);
5472 iscan->timer.data = (unsigned long) iscan;
5473 iscan->timer.function = wl_iscan_timer;
5474 sema_init(&iscan->sync, 0);
5475 iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
5476 if (IS_ERR(iscan->tsk)) {
5477 WL_ERR(("Could not create iscan thread\n"));
5478 iscan->tsk = NULL;
5479 return -ENOMEM;
5480 }
5481 iscan->data = wl;
5482 } else if (wl->escan_on) {
5483 wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
5484 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5485 }
5486 /* Init scan_timeout timer */
5487 init_timer(&wl->scan_timeout);
5488 wl->scan_timeout.data = (unsigned long) wl;
5489 wl->scan_timeout.function = wl_scan_timeout;
5490
5491 return err;
5492}
5493
5494static void wl_init_fw(struct wl_fw_ctrl *fw)
5495{
5496 fw->status = 0;
5497}
5498
5499static s32 wl_init_priv(struct wl_priv *wl)
5500{
5501 struct wiphy *wiphy = wl_to_wiphy(wl);
5502 s32 err = 0;
5503 s32 i = 0;
5504
5505 wl->scan_request = NULL;
5506 wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
5507 wl->iscan_on = false;
5508 wl->escan_on = true;
5509 wl->roam_on = false;
5510 wl->iscan_kickstart = false;
5511 wl->active_scan = true;
5512 wl->dongle_up = false;
5513 wl->rf_blocked = false;
5514
5515 for (i = 0; i < VWDEV_CNT; i++)
5516 wl->vwdev[i] = NULL;
5517
5518 init_waitqueue_head(&wl->dongle_event_wait);
5519 wl_init_eq(wl);
5520 err = wl_init_priv_mem(wl);
5521 if (unlikely(err))
5522 return err;
5523 if (unlikely(wl_create_event_handler(wl)))
5524 return -ENOMEM;
5525 wl_init_event_handler(wl);
5526 mutex_init(&wl->usr_sync);
5527 err = wl_init_scan(wl);
5528 if (unlikely(err))
5529 return err;
5530 wl_init_fw(wl->fw);
5531 wl_init_conf(wl->conf);
5532 wl_init_prof(wl);
5533 wl_link_down(wl);
5534
5535 return err;
5536}
5537
5538static void wl_deinit_priv(struct wl_priv *wl)
5539{
5540 wl_destroy_event_handler(wl);
5541 wl->dongle_up = false; /* dongle down */
5542 wl_flush_eq(wl);
5543 wl_link_down(wl);
5544 del_timer_sync(&wl->scan_timeout);
5545 wl_term_iscan(wl);
5546 wl_deinit_priv_mem(wl);
5547}
5548
5549#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5550s32 wl_cfg80211_sysctl_export_devaddr(void *data)
5551{
5552 /* Export the p2p_dev_addr via sysctl interface
5553 * so that wpa_supplicant can access it
5554 */
5555 dhd_pub_t *dhd = (dhd_pub_t *)data;
5556 struct wl_priv *wl = wlcfg_drv_priv;
5557
5558 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
5559
5560 sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet));
5561 sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet));
5562
5563 return 0;
5564}
5565#endif /* CONFIG_SYSCTL */
5566
5567s32 wl_cfg80211_attach_post(struct net_device *ndev)
5568{
5569 struct wl_priv * wl = NULL;
5570 s32 err = 0;
5571 WL_TRACE(("In\n"));
5572 if (unlikely(!ndev)) {
5573 WL_ERR(("ndev is invaild\n"));
5574 return -ENODEV;
5575 }
5576 wl = wlcfg_drv_priv;
5577 if (wl && !wl_get_drv_status(wl, READY)) {
5578 if (wl->wdev &&
5579 wl_cfgp2p_supported(wl, ndev)) {
5580 wl->wdev->wiphy->interface_modes |=
5581 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
5582 BIT(NL80211_IFTYPE_P2P_GO));
5583 if ((err = wl_cfgp2p_init_priv(wl)) != 0)
5584 goto fail;
5585#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5586 wl_cfg80211_sysctl_export_devaddr(wl->pub);
5587#endif
5588 wl->p2p_supported = true;
5589 }
5590 } else
5591 return -ENODEV;
5592
5593 wl_set_drv_status(wl, READY);
5594fail:
5595 return err;
5596}
5597s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
5598{
5599 struct wireless_dev *wdev;
5600 struct wl_priv *wl;
5601 s32 err = 0;
5602
5603 WL_TRACE(("In\n"));
5604 if (unlikely(!ndev)) {
5605 WL_ERR(("ndev is invaild\n"));
5606 return -ENODEV;
5607 }
5608 WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
5609 wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev);
5610 if (unlikely(IS_ERR(wdev)))
5611 return -ENOMEM;
5612
5613 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
5614 wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
5615 wl->wdev = wdev;
5616 wl->pub = data;
5617
5618 ndev->ieee80211_ptr = wdev;
5619 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
5620 wdev->netdev = ndev;
5621
5622 err = wl_init_priv(wl);
5623 if (unlikely(err)) {
5624 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
5625 goto cfg80211_attach_out;
5626 }
5627
5628 err = wl_setup_rfkill(wl, TRUE);
5629 if (unlikely(err)) {
5630 WL_ERR(("Failed to setup rfkill %d\n", err));
5631 goto cfg80211_attach_out;
5632 }
5633
5634#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5635 if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) {
5636 WL_ERR(("%s: sysctl register failed!! \n", __func__));
5637 goto cfg80211_attach_out;
5638 }
5639#endif
5640#if defined(COEX_DHCP)
5641 if (wl_cfg80211_btcoex_init(wl))
5642 goto cfg80211_attach_out;
5643#endif /* COEX_DHCP */
5644
5645 wlcfg_drv_priv = wl;
5646 return err;
5647
5648cfg80211_attach_out:
5649 err = wl_setup_rfkill(wl, FALSE);
5650 wl_free_wdev(wl);
5651 return err;
5652}
5653
5654void wl_cfg80211_detach(void)
5655{
5656 struct wl_priv *wl;
5657
5658 wl = wlcfg_drv_priv;
5659
5660 WL_TRACE(("In\n"));
5661
5662#if defined(COEX_DHCP)
5663 wl_cfg80211_btcoex_deinit(wl);
5664#endif /* COEX_DHCP */
5665
5666#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5667 if (wl_sysctl_hdr)
5668 unregister_sysctl_table(wl_sysctl_hdr);
5669#endif
5670 wl_setup_rfkill(wl, FALSE);
5671 if (wl->p2p_supported)
5672 wl_cfgp2p_deinit_priv(wl);
5673 wl_deinit_priv(wl);
5674 wlcfg_drv_priv = NULL;
5675 wl_clear_sdio_func();
5676 wl_free_wdev(wl);
5677}
5678
5679static void wl_wakeup_event(struct wl_priv *wl)
5680{
5681 if (wl->event_tsk.thr_pid >= 0) {
5682 DHD_OS_WAKE_LOCK(wl->pub);
5683 up(&wl->event_tsk.sema);
5684 }
5685}
5686
5687static s32 wl_event_handler(void *data)
5688{
5689 struct net_device *netdev;
5690 struct wl_priv *wl = NULL;
5691 struct wl_event_q *e;
5692 tsk_ctl_t *tsk = (tsk_ctl_t *)data;
5693
5694 wl = (struct wl_priv *)tsk->parent;
5695 complete(&tsk->completed);
5696
5697 while (down_interruptible (&tsk->sema) == 0) {
5698 SMP_RD_BARRIER_DEPENDS();
5699 if (tsk->terminated)
5700 break;
5701 while ((e = wl_deq_event(wl))) {
5702 WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
5703 netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
5704 if (!netdev)
5705 netdev = wl_to_prmry_ndev(wl);
5706 if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
5707 wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
5708 } else {
5709 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
5710 }
5711 wl_put_event(e);
5712 }
5713 DHD_OS_WAKE_UNLOCK(wl->pub);
5714 }
5715 WL_DBG(("%s was terminated\n", __func__));
5716 complete_and_exit(&tsk->completed, 0);
5717 return 0;
5718}
5719
5720void
5721wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
5722{
5723 u32 event_type = ntoh32(e->event_type);
5724 struct wl_priv *wl = wlcfg_drv_priv;
5725
5726#if (WL_DBG_LEVEL > 0)
5727 s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
5728 wl_dbg_estr[event_type] : (s8 *) "Unknown";
5729 WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
5730#endif /* (WL_DBG_LEVEL > 0) */
5731
5732 if (event_type == WLC_E_PFN_NET_FOUND)
5733 WL_ERR((" PNO Event\n"));
5734
5735 if (likely(!wl_enq_event(wl, ndev, event_type, e, data)))
5736 wl_wakeup_event(wl);
5737}
5738
5739static void wl_init_eq(struct wl_priv *wl)
5740{
5741 wl_init_eq_lock(wl);
5742 INIT_LIST_HEAD(&wl->eq_list);
5743}
5744
5745static void wl_flush_eq(struct wl_priv *wl)
5746{
5747 struct wl_event_q *e;
5748 unsigned long flags;
5749
5750 flags = wl_lock_eq(wl);
5751 while (!list_empty(&wl->eq_list)) {
5752 e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
5753 list_del(&e->eq_list);
5754 kfree(e);
5755 }
5756 wl_unlock_eq(wl, flags);
5757}
5758
5759/*
5760* retrieve first queued event from head
5761*/
5762
5763static struct wl_event_q *wl_deq_event(struct wl_priv *wl)
5764{
5765 struct wl_event_q *e = NULL;
5766 unsigned long flags;
5767
5768 flags = wl_lock_eq(wl);
5769 if (likely(!list_empty(&wl->eq_list))) {
5770 e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
5771 list_del(&e->eq_list);
5772 }
5773 wl_unlock_eq(wl, flags);
5774
5775 return e;
5776}
5777
5778/*
5779 * push event to tail of the queue
5780 */
5781
5782static s32
5783wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg,
5784 void *data)
5785{
5786 struct wl_event_q *e;
5787 s32 err = 0;
5788 uint32 evtq_size;
5789 uint32 data_len;
5790 unsigned long flags;
5791 gfp_t aflags;
5792
5793 data_len = 0;
5794 if (data)
5795 data_len = ntoh32(msg->datalen);
5796 evtq_size = sizeof(struct wl_event_q) + data_len;
5797 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
5798 e = kzalloc(evtq_size, aflags);
5799 if (unlikely(!e)) {
5800 WL_ERR(("event alloc failed\n"));
5801 return -ENOMEM;
5802 }
5803 e->etype = event;
5804 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
5805 if (data)
5806 memcpy(e->edata, data, data_len);
5807 flags = wl_lock_eq(wl);
5808 list_add_tail(&e->eq_list, &wl->eq_list);
5809 wl_unlock_eq(wl, flags);
5810
5811 return err;
5812}
5813
5814static void wl_put_event(struct wl_event_q *e)
5815{
5816 kfree(e);
5817}
5818
5819void wl_cfg80211_set_sdio_func(void *func)
5820{
5821 cfg80211_sdio_func = (struct sdio_func *)func;
5822}
5823
5824static void wl_clear_sdio_func(void)
5825{
5826 cfg80211_sdio_func = NULL;
5827}
5828
5829struct sdio_func *wl_cfg80211_get_sdio_func(void)
5830{
5831 return cfg80211_sdio_func;
5832}
5833
5834static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
5835{
5836 s32 infra = 0;
5837 s32 err = 0;
5838 s32 mode = 0;
5839 switch (iftype) {
5840 case NL80211_IFTYPE_MONITOR:
5841 case NL80211_IFTYPE_WDS:
5842 WL_ERR(("type (%d) : currently we do not support this mode\n",
5843 iftype));
5844 err = -EINVAL;
5845 return err;
5846 case NL80211_IFTYPE_ADHOC:
5847 mode = WL_MODE_IBSS;
5848 break;
5849 case NL80211_IFTYPE_STATION:
5850 case NL80211_IFTYPE_P2P_CLIENT:
5851 mode = WL_MODE_BSS;
5852 infra = 1;
5853 break;
5854 case NL80211_IFTYPE_AP:
5855 case NL80211_IFTYPE_P2P_GO:
5856 mode = WL_MODE_AP;
5857 infra = 1;
5858 break;
5859 default:
5860 err = -EINVAL;
5861 WL_ERR(("invalid type (%d)\n", iftype));
5862 return err;
5863 }
5864 infra = htod32(infra);
5865 err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
5866 if (unlikely(err)) {
5867 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
5868 return err;
5869 }
5870
5871 set_mode_by_netdev(wl, ndev, mode);
5872
5873 return 0;
5874}
5875static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
5876{
5877 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5878
5879 s8 eventmask[WL_EVENTING_MASK_LEN];
5880 s32 err = 0;
5881
5882 /* Setup event_msgs */
5883 bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
5884 sizeof(iovbuf));
5885 err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
5886 if (unlikely(err)) {
5887 WL_ERR(("Get event_msgs error (%d)\n", err));
5888 goto dongle_eventmsg_out;
5889 }
5890 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
5891 if (add) {
5892 setbit(eventmask, event);
5893 } else {
5894 clrbit(eventmask, event);
5895 }
5896 bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
5897 sizeof(iovbuf));
5898 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5899 if (unlikely(err)) {
5900 WL_ERR(("Set event_msgs error (%d)\n", err));
5901 goto dongle_eventmsg_out;
5902 }
5903
5904dongle_eventmsg_out:
5905 return err;
5906
5907}
5908
5909
5910#ifndef EMBEDDED_PLATFORM
5911static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
5912{
5913
5914 s32 err = 0;
5915
5916 return err;
5917}
5918
5919static s32 wl_dongle_up(struct net_device *ndev, u32 up)
5920{
5921 s32 err = 0;
5922
5923 err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
5924 if (unlikely(err)) {
5925 WL_ERR(("WLC_UP error (%d)\n", err));
5926 }
5927 return err;
5928}
5929
5930static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
5931{
5932 s32 err = 0;
5933
5934 WL_TRACE(("In\n"));
5935 err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
5936 if (unlikely(err)) {
5937 WL_ERR(("WLC_SET_PM error (%d)\n", err));
5938 }
5939 return err;
5940}
5941
5942static s32
5943wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
5944{
5945 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5946
5947 s32 err = 0;
5948
5949 /* Match Host and Dongle rx alignment */
5950 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
5951 sizeof(iovbuf));
5952 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5953 if (unlikely(err)) {
5954 WL_ERR(("txglomalign error (%d)\n", err));
5955 goto dongle_glom_out;
5956 }
5957 /* disable glom option per default */
5958 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
5959 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5960 if (unlikely(err)) {
5961 WL_ERR(("txglom error (%d)\n", err));
5962 goto dongle_glom_out;
5963 }
5964dongle_glom_out:
5965 return err;
5966}
5967
5968static s32
5969wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
5970{
5971 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5972
5973 s32 err = 0;
5974
5975 /* Setup timeout if Beacons are lost and roam is off to report link down */
5976 if (roamvar) {
5977 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
5978 sizeof(iovbuf));
5979 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5980 if (unlikely(err)) {
5981 WL_ERR(("bcn_timeout error (%d)\n", err));
5982 goto dongle_rom_out;
5983 }
5984 }
5985 /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
5986 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
5987 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5988 if (unlikely(err)) {
5989 WL_ERR(("roam_off error (%d)\n", err));
5990 goto dongle_rom_out;
5991 }
5992dongle_rom_out:
5993 return err;
5994}
5995
5996static s32
5997wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
5998 s32 scan_unassoc_time)
5999{
6000 s32 err = 0;
6001
6002 err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
6003 sizeof(scan_assoc_time), true);
6004 if (err) {
6005 if (err == -EOPNOTSUPP) {
6006 WL_INFO(("Scan assoc time is not supported\n"));
6007 } else {
6008 WL_ERR(("Scan assoc time error (%d)\n", err));
6009 }
6010 goto dongle_scantime_out;
6011 }
6012 err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
6013 sizeof(scan_unassoc_time), true);
6014 if (err) {
6015 if (err == -EOPNOTSUPP) {
6016 WL_INFO(("Scan unassoc time is not supported\n"));
6017 } else {
6018 WL_ERR(("Scan unassoc time error (%d)\n", err));
6019 }
6020 goto dongle_scantime_out;
6021 }
6022
6023dongle_scantime_out:
6024 return err;
6025}
6026
6027static s32
6028wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
6029{
6030 /* Room for "event_msgs" + '\0' + bitvec */
6031 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
6032
6033 s32 err = 0;
6034
6035 /* Set ARP offload */
6036 bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
6037 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
6038 if (err) {
6039 if (err == -EOPNOTSUPP)
6040 WL_INFO(("arpoe is not supported\n"));
6041 else
6042 WL_ERR(("arpoe error (%d)\n", err));
6043
6044 goto dongle_offload_out;
6045 }
6046 bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
6047 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
6048 if (err) {
6049 if (err == -EOPNOTSUPP)
6050 WL_INFO(("arp_ol is not supported\n"));
6051 else
6052 WL_ERR(("arp_ol error (%d)\n", err));
6053
6054 goto dongle_offload_out;
6055 }
6056
6057dongle_offload_out:
6058 return err;
6059}
6060
6061static s32 wl_pattern_atoh(s8 *src, s8 *dst)
6062{
6063 int i;
6064 if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
6065 WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
6066 return -1;
6067 }
6068 src = src + 2; /* Skip past 0x */
6069 if (strlen(src) % 2 != 0) {
6070 WL_ERR(("Mask invalid format. Needs to be of even length\n"));
6071 return -1;
6072 }
6073 for (i = 0; *src != '\0'; i++) {
6074 char num[3];
6075 strncpy(num, src, 2);
6076 num[2] = '\0';
6077 dst[i] = (u8) simple_strtoul(num, NULL, 16);
6078 src += 2;
6079 }
6080 return i;
6081}
6082
6083static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
6084{
6085 /* Room for "event_msgs" + '\0' + bitvec */
6086 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
6087
6088 const s8 *str;
6089 struct wl_pkt_filter pkt_filter;
6090 struct wl_pkt_filter *pkt_filterp;
6091 s32 buf_len;
6092 s32 str_len;
6093 u32 mask_size;
6094 u32 pattern_size;
6095 s8 buf[256];
6096 s32 err = 0;
6097
6098 /* add a default packet filter pattern */
6099 str = "pkt_filter_add";
6100 str_len = strlen(str);
6101 strncpy(buf, str, str_len);
6102 buf[str_len] = '\0';
6103 buf_len = str_len + 1;
6104
6105 pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
6106
6107 /* Parse packet filter id. */
6108 pkt_filter.id = htod32(100);
6109
6110 /* Parse filter polarity. */
6111 pkt_filter.negate_match = htod32(0);
6112
6113 /* Parse filter type. */
6114 pkt_filter.type = htod32(0);
6115
6116 /* Parse pattern filter offset. */
6117 pkt_filter.u.pattern.offset = htod32(0);
6118
6119 /* Parse pattern filter mask. */
6120 mask_size = htod32(wl_pattern_atoh("0xff",
6121 (char *)pkt_filterp->u.pattern.
6122 mask_and_pattern));
6123
6124 /* Parse pattern filter pattern. */
6125 pattern_size = htod32(wl_pattern_atoh("0x00",
6126 (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
6127
6128 if (mask_size != pattern_size) {
6129 WL_ERR(("Mask and pattern not the same size\n"));
6130 err = -EINVAL;
6131 goto dongle_filter_out;
6132 }
6133
6134 pkt_filter.u.pattern.size_bytes = mask_size;
6135 buf_len += WL_PKT_FILTER_FIXED_LEN;
6136 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
6137
6138 /* Keep-alive attributes are set in local
6139 * variable (keep_alive_pkt), and
6140 * then memcpy'ed into buffer (keep_alive_pktp) since there is no
6141 * guarantee that the buffer is properly aligned.
6142 */
6143 memcpy((char *)pkt_filterp, &pkt_filter,
6144 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
6145
6146 err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
6147 if (err) {
6148 if (err == -EOPNOTSUPP) {
6149 WL_INFO(("filter not supported\n"));
6150 } else {
6151 WL_ERR(("filter (%d)\n", err));
6152 }
6153 goto dongle_filter_out;
6154 }
6155
6156 /* set mode to allow pattern */
6157 bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
6158 sizeof(iovbuf));
6159 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
6160 if (err) {
6161 if (err == -EOPNOTSUPP) {
6162 WL_INFO(("filter_mode not supported\n"));
6163 } else {
6164 WL_ERR(("filter_mode (%d)\n", err));
6165 }
6166 goto dongle_filter_out;
6167 }
6168
6169dongle_filter_out:
6170 return err;
6171}
6172#endif /* !EMBEDDED_PLATFORM */
6173
6174s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
6175{
6176#ifndef DHD_SDALIGN
6177#define DHD_SDALIGN 32
6178#endif
6179 struct net_device *ndev;
6180 struct wireless_dev *wdev;
6181 s32 err = 0;
6182
6183 WL_TRACE(("In\n"));
6184 if (wl->dongle_up) {
6185 WL_ERR(("Dongle is already up\n"));
6186 return err;
6187 }
6188
6189 ndev = wl_to_prmry_ndev(wl);
6190 wdev = ndev->ieee80211_ptr;
6191 if (need_lock)
6192 rtnl_lock();
6193#ifndef EMBEDDED_PLATFORM
6194 err = wl_dongle_up(ndev, 0);
6195 if (unlikely(err)) {
6196 WL_ERR(("wl_dongle_up failed\n"));
6197 goto default_conf_out;
6198 }
6199 err = wl_dongle_country(ndev, 0);
6200 if (unlikely(err)) {
6201 WL_ERR(("wl_dongle_country failed\n"));
6202 goto default_conf_out;
6203 }
6204 err = wl_dongle_power(ndev, PM_FAST);
6205 if (unlikely(err)) {
6206 WL_ERR(("wl_dongle_power failed\n"));
6207 goto default_conf_out;
6208 }
6209 err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
6210 if (unlikely(err)) {
6211 WL_ERR(("wl_dongle_glom failed\n"));
6212 goto default_conf_out;
6213 }
6214 err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
6215 if (unlikely(err)) {
6216 WL_ERR(("wl_dongle_roam failed\n"));
6217 goto default_conf_out;
6218 }
6219 wl_dongle_scantime(ndev, 40, 80);
6220 wl_dongle_offload(ndev, 1, 0xf);
6221 wl_dongle_filter(ndev, 1);
6222#endif /* !EMBEDDED_PLATFORM */
6223
6224 err = wl_dongle_mode(wl, ndev, wdev->iftype);
6225 if (unlikely(err && err != -EINPROGRESS)) {
6226 WL_ERR(("wl_dongle_mode failed\n"));
6227 goto default_conf_out;
6228 }
6229 err = wl_dongle_probecap(wl);
6230 if (unlikely(err)) {
6231 WL_ERR(("wl_dongle_probecap failed\n"));
6232 goto default_conf_out;
6233 }
6234
6235 /* -EINPROGRESS: Call commit handler */
6236
6237default_conf_out:
6238 if (need_lock)
6239 rtnl_unlock();
6240
6241 wl->dongle_up = true;
6242
6243 return err;
6244
6245}
6246
6247static s32 wl_update_wiphybands(struct wl_priv *wl)
6248{
6249 struct wiphy *wiphy;
6250 s8 phylist_buf[128];
6251 s8 *phy;
6252 s32 err = 0;
6253
6254 err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
6255 sizeof(phylist_buf), false);
6256 if (unlikely(err)) {
6257 WL_ERR(("error (%d)\n", err));
6258 return err;
6259 }
6260 phy = phylist_buf;
6261 for (; *phy; phy++) {
6262 if (*phy == 'a' || *phy == 'n') {
6263 wiphy = wl_to_wiphy(wl);
6264 wiphy->bands[IEEE80211_BAND_5GHZ] =
6265 &__wl_band_5ghz_a;
6266 }
6267 }
6268 return err;
6269}
6270
6271static s32 __wl_cfg80211_up(struct wl_priv *wl)
6272{
6273 s32 err = 0;
6274
6275 WL_TRACE(("In\n"));
6276 wl_debugfs_add_netdev_params(wl);
6277
6278 err = wl_config_dongle(wl, false);
6279 if (unlikely(err))
6280 return err;
6281 dhd_monitor_init(wl->pub);
6282 wl_invoke_iscan(wl);
6283 wl_set_drv_status(wl, READY);
6284 return err;
6285}
6286
6287static s32 __wl_cfg80211_down(struct wl_priv *wl)
6288{
6289 s32 err = 0;
6290 unsigned long flags;
6291
6292 WL_TRACE(("In\n"));
6293 /* Check if cfg80211 interface is already down */
6294 if (!wl_get_drv_status(wl, READY))
6295 return err; /* it is even not ready */
6296
6297 wl_set_drv_status(wl, SCAN_ABORTING);
6298
6299 wl_term_iscan(wl);
6300 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
6301 if (wl->scan_request) {
6302 cfg80211_scan_done(wl->scan_request, true);
6303 wl->scan_request = NULL;
6304 }
6305 wl_clr_drv_status(wl, READY);
6306 wl_clr_drv_status(wl, SCANNING);
6307 wl_clr_drv_status(wl, SCAN_ABORTING);
6308 wl_clr_drv_status(wl, CONNECTING);
6309 wl_clr_drv_status(wl, CONNECTED);
6310 wl_clr_drv_status(wl, DISCONNECTING);
6311 if (wl_get_drv_status(wl, AP_CREATED)) {
6312 wl_clr_drv_status(wl, AP_CREATED);
6313 wl_clr_drv_status(wl, AP_CREATING);
6314 }
6315 wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
6316 NL80211_IFTYPE_STATION;
6317 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
6318
6319 wl->dongle_up = false;
6320 wl_flush_eq(wl);
6321 wl_link_down(wl);
6322 if (wl->p2p_supported)
6323 wl_cfgp2p_down(wl);
6324 dhd_monitor_uninit();
6325
6326 wl_debugfs_remove_netdev(wl);
6327
6328 return err;
6329}
6330
6331s32 wl_cfg80211_up(void)
6332{
6333 struct wl_priv *wl;
6334 s32 err = 0;
6335
6336 WL_TRACE(("In\n"));
6337 wl = wlcfg_drv_priv;
6338 mutex_lock(&wl->usr_sync);
6339 wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
6340 err = __wl_cfg80211_up(wl);
6341 if (err)
6342 WL_ERR(("__wl_cfg80211_up failed\n"));
6343 mutex_unlock(&wl->usr_sync);
6344
6345 return err;
6346}
6347
6348/* Private Event to Supplicant with indication that FW hangs */
6349int wl_cfg80211_hang(struct net_device *dev, u16 reason)
6350{
6351 struct wl_priv *wl;
6352 wl = wlcfg_drv_priv;
6353
6354 WL_ERR(("In : FW crash Eventing\n"));
6355 cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
6356 if (wl != NULL) {
6357 wl_link_down(wl);
6358 }
6359 return 0;
6360}
6361
6362s32 wl_cfg80211_down(void)
6363{
6364 struct wl_priv *wl;
6365 s32 err = 0;
6366
6367 WL_TRACE(("In\n"));
6368 wl = wlcfg_drv_priv;
6369 mutex_lock(&wl->usr_sync);
6370 err = __wl_cfg80211_down(wl);
6371 mutex_unlock(&wl->usr_sync);
6372
6373 return err;
6374}
6375
6376static s32 wl_dongle_probecap(struct wl_priv *wl)
6377{
6378 s32 err = 0;
6379
6380 err = wl_update_wiphybands(wl);
6381 if (unlikely(err))
6382 return err;
6383
6384 return err;
6385}
6386
6387static void *wl_read_prof(struct wl_priv *wl, s32 item)
6388{
6389 unsigned long flags;
6390 void *rptr = NULL;
6391
6392 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
6393 switch (item) {
6394 case WL_PROF_SEC:
6395 rptr = &wl->profile->sec;
6396 break;
6397 case WL_PROF_ACT:
6398 rptr = &wl->profile->active;
6399 break;
6400 case WL_PROF_BSSID:
6401 rptr = &wl->profile->bssid;
6402 break;
6403 case WL_PROF_SSID:
6404 rptr = &wl->profile->ssid;
6405 break;
6406 }
6407 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
6408 if (!rptr)
6409 WL_ERR(("invalid item (%d)\n", item));
6410 return rptr;
6411}
6412
6413static s32
6414wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
6415 s32 item)
6416{
6417 s32 err = 0;
6418 struct wlc_ssid *ssid;
6419 unsigned long flags;
6420
6421 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
6422 switch (item) {
6423 case WL_PROF_SSID:
6424 ssid = (wlc_ssid_t *) data;
6425 memset(wl->profile->ssid.SSID, 0,
6426 sizeof(wl->profile->ssid.SSID));
6427 memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
6428 wl->profile->ssid.SSID_len = ssid->SSID_len;
6429 break;
6430 case WL_PROF_BSSID:
6431 if (data)
6432 memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
6433 else
6434 memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
6435 break;
6436 case WL_PROF_SEC:
6437 memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
6438 break;
6439 case WL_PROF_ACT:
6440 wl->profile->active = *(bool *)data;
6441 break;
6442 case WL_PROF_BEACONINT:
6443 wl->profile->beacon_interval = *(u16 *)data;
6444 break;
6445 case WL_PROF_DTIMPERIOD:
6446 wl->profile->dtim_period = *(u8 *)data;
6447 break;
6448 default:
6449 WL_ERR(("unsupported item (%d)\n", item));
6450 err = -EOPNOTSUPP;
6451 break;
6452 }
6453 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
6454 return err;
6455}
6456
6457void wl_cfg80211_dbg_level(u32 level)
6458{
6459 /*
6460 * prohibit to change debug level
6461 * by insmod parameter.
6462 * eventually debug level will be configured
6463 * in compile time by using CONFIG_XXX
6464 */
6465 /* wl_dbg_level = level; */
6466}
6467
6468static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev)
6469{
6470 return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
6471}
6472
6473static __used bool wl_is_ibssstarter(struct wl_priv *wl)
6474{
6475 return wl->ibss_starter;
6476}
6477
6478static void wl_rst_ie(struct wl_priv *wl)
6479{
6480 struct wl_ie *ie = wl_to_ie(wl);
6481
6482 ie->offset = 0;
6483}
6484
6485static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
6486{
6487 struct wl_ie *ie = wl_to_ie(wl);
6488 s32 err = 0;
6489
6490 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
6491 WL_ERR(("ei crosses buffer boundary\n"));
6492 return -ENOSPC;
6493 }
6494 ie->buf[ie->offset] = t;
6495 ie->buf[ie->offset + 1] = l;
6496 memcpy(&ie->buf[ie->offset + 2], v, l);
6497 ie->offset += l + 2;
6498
6499 return err;
6500}
6501
6502static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size)
6503{
6504 struct wl_ie *ie = wl_to_ie(wl);
6505 s32 err = 0;
6506
6507 if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
6508 WL_ERR(("ei_stream crosses buffer boundary\n"));
6509 return -ENOSPC;
6510 }
6511 memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
6512 ie->offset += ie_size;
6513
6514 return err;
6515}
6516
6517static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size)
6518{
6519 struct wl_ie *ie = wl_to_ie(wl);
6520 s32 err = 0;
6521
6522 if (unlikely(ie->offset > dst_size)) {
6523 WL_ERR(("dst_size is not enough\n"));
6524 return -ENOSPC;
6525 }
6526 memcpy(dst, &ie->buf[0], ie->offset);
6527
6528 return err;
6529}
6530
6531static u32 wl_get_ielen(struct wl_priv *wl)
6532{
6533 struct wl_ie *ie = wl_to_ie(wl);
6534
6535 return ie->offset;
6536}
6537
6538static void wl_link_up(struct wl_priv *wl)
6539{
6540 wl->link_up = true;
6541}
6542
6543static void wl_link_down(struct wl_priv *wl)
6544{
6545 struct wl_connect_info *conn_info = wl_to_conn(wl);
6546
6547 WL_DBG(("In\n"));
6548 wl->link_up = false;
6549 conn_info->req_ie_len = 0;
6550 conn_info->resp_ie_len = 0;
6551}
6552
6553static unsigned long wl_lock_eq(struct wl_priv *wl)
6554{
6555 unsigned long flags;
6556
6557 spin_lock_irqsave(&wl->eq_lock, flags);
6558 return flags;
6559}
6560
6561static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags)
6562{
6563 spin_unlock_irqrestore(&wl->eq_lock, flags);
6564}
6565
6566static void wl_init_eq_lock(struct wl_priv *wl)
6567{
6568 spin_lock_init(&wl->eq_lock);
6569}
6570
6571static void wl_delay(u32 ms)
6572{
6573 if (ms < 1000 / HZ) {
6574 cond_resched();
6575 mdelay(ms);
6576 } else {
6577 msleep(ms);
6578 }
6579}
6580
6581s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
6582{
6583 const struct firmware *fw_entry;
6584 struct wl_priv *wl;
6585
6586 wl = wlcfg_drv_priv;
6587
6588 fw_entry = wl->fw->fw_entry;
6589
6590 if (fw_entry->size < wl->fw->ptr + size)
6591 size = fw_entry->size - wl->fw->ptr;
6592
6593 memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
6594 wl->fw->ptr += size;
6595 return size;
6596}
6597
6598void wl_cfg80211_release_fw(void)
6599{
6600 struct wl_priv *wl;
6601
6602 wl = wlcfg_drv_priv;
6603 release_firmware(wl->fw->fw_entry);
6604 wl->fw->ptr = 0;
6605}
6606
6607void *wl_cfg80211_request_fw(s8 *file_name)
6608{
6609 struct wl_priv *wl;
6610 const struct firmware *fw_entry = NULL;
6611 s32 err = 0;
6612
6613 WL_TRACE(("In\n"));
6614 WL_DBG(("file name : \"%s\"\n", file_name));
6615 wl = wlcfg_drv_priv;
6616
6617 if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
6618 err = request_firmware(&wl->fw->fw_entry, file_name,
6619 &wl_cfg80211_get_sdio_func()->dev);
6620 if (unlikely(err)) {
6621 WL_ERR(("Could not download fw (%d)\n", err));
6622 goto req_fw_out;
6623 }
6624 set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
6625 fw_entry = wl->fw->fw_entry;
6626 if (fw_entry) {
6627 WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
6628 fw_entry->data));
6629 }
6630 } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
6631 err = request_firmware(&wl->fw->fw_entry, file_name,
6632 &wl_cfg80211_get_sdio_func()->dev);
6633 if (unlikely(err)) {
6634 WL_ERR(("Could not download nvram (%d)\n", err));
6635 goto req_fw_out;
6636 }
6637 set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
6638 fw_entry = wl->fw->fw_entry;
6639 if (fw_entry) {
6640 WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
6641 fw_entry->data));
6642 }
6643 } else {
6644 WL_DBG(("Downloading already done. Nothing to do more\n"));
6645 err = -EPERM;
6646 }
6647
6648req_fw_out:
6649 if (unlikely(err)) {
6650 return NULL;
6651 }
6652 wl->fw->ptr = 0;
6653 return (void *)fw_entry->data;
6654}
6655
6656s8 *wl_cfg80211_get_fwname(void)
6657{
6658 struct wl_priv *wl;
6659
6660 wl = wlcfg_drv_priv;
6661 strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
6662 return wl->fw->fw_name;
6663}
6664
6665s8 *wl_cfg80211_get_nvramname(void)
6666{
6667 struct wl_priv *wl;
6668
6669 wl = wlcfg_drv_priv;
6670 strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
6671 return wl->fw->nvram_name;
6672}
6673
6674s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
6675{
6676 struct wl_priv *wl;
6677 dhd_pub_t *dhd_pub;
6678 struct ether_addr p2pif_addr;
6679
6680 wl = wlcfg_drv_priv;
6681 dhd_pub = (dhd_pub_t *)wl->pub;
6682 wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
6683
6684 return 0;
6685}
6686s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
6687{
6688 struct wl_priv *wl;
6689 wl = wlcfg_drv_priv;
6690
6691 return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
6692}
6693
6694s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
6695{
6696 struct wl_priv *wl;
6697 wl = wlcfg_drv_priv;
6698
6699 return wl_cfgp2p_get_p2p_noa(wl, net, buf, len);
6700}
6701
6702s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
6703{
6704 struct wl_priv *wl;
6705 wl = wlcfg_drv_priv;
6706
6707 return wl_cfgp2p_set_p2p_ps(wl, net, buf, len);
6708}
6709
6710s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
6711 enum wl_management_type type)
6712{
6713 struct wl_priv *wl;
6714 struct net_device *ndev = NULL;
6715 s32 ret = 0;
6716 s32 bssidx = 0;
6717 s32 pktflag = 0;
6718 wl = wlcfg_drv_priv;
6719 if (wl->p2p && wl->p2p->vif_created) {
6720 ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
6721 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
6722 } else if (wl_get_drv_status(wl, AP_CREATING) ||
6723 wl_get_drv_status(wl, AP_CREATED)) {
6724 ndev = net;
6725 bssidx = 0;
6726 }
6727 if (ndev != NULL) {
6728 switch (type) {
6729 case WL_BEACON:
6730 pktflag = VNDR_IE_BEACON_FLAG;
6731 break;
6732 case WL_PROBE_RESP:
6733 pktflag = VNDR_IE_PRBRSP_FLAG;
6734 break;
6735 case WL_ASSOC_RESP:
6736 pktflag = VNDR_IE_ASSOCRSP_FLAG;
6737 break;
6738 }
6739 if (pktflag)
6740 ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len);
6741 }
6742
6743 return ret;
6744}
6745
6746static __used void wl_dongle_poweron(struct wl_priv *wl)
6747{
6748 WL_DBG(("Enter \n"));
6749 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
6750
6751#if defined(BCMLXSDMMC)
6752 sdioh_start(NULL, 0);
6753#endif
6754#if defined(BCMLXSDMMC)
6755 sdioh_start(NULL, 1);
6756#endif
6757 wl_cfg80211_resume(wl_to_wiphy(wl));
6758}
6759
6760static __used void wl_dongle_poweroff(struct wl_priv *wl)
6761{
6762 WL_DBG(("Enter \n"));
6763#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
6764 wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
6765#else
6766 wl_cfg80211_suspend(wl_to_wiphy(wl));
6767#endif
6768
6769#if defined(BCMLXSDMMC)
6770 sdioh_stop(NULL);
6771#endif
6772 /* clean up dtim_skip setting */
6773 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
6774}
6775
6776static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
6777{
6778 char buf[10+IFNAMSIZ];
6779 struct dentry *fd;
6780 s32 err = 0;
6781
6782 WL_TRACE(("In\n"));
6783 sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name);
6784 wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
6785
6786 fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
6787 (u16 *)&wl->profile->beacon_interval);
6788 if (!fd) {
6789 err = -ENOMEM;
6790 goto err_out;
6791 }
6792
6793 fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
6794 (u8 *)&wl->profile->dtim_period);
6795 if (!fd) {
6796 err = -ENOMEM;
6797 goto err_out;
6798 }
6799
6800err_out:
6801 return err;
6802}
6803
6804static void wl_debugfs_remove_netdev(struct wl_priv *wl)
6805{
6806 WL_DBG(("Enter \n"));
6807}
6808
6809static const struct rfkill_ops wl_rfkill_ops = {
6810 .set_block = wl_rfkill_set
6811};
6812
6813static int wl_rfkill_set(void *data, bool blocked)
6814{
6815 struct wl_priv *wl = (struct wl_priv *)data;
6816
6817 WL_DBG(("Enter \n"));
6818 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
6819
6820 if (!wl)
6821 return -EINVAL;
6822
6823 wl->rf_blocked = blocked;
6824
6825 return 0;
6826}
6827
6828static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
6829{
6830 s32 err = 0;
6831
6832 WL_DBG(("Enter \n"));
6833 if (!wl)
6834 return -EINVAL;
6835 if (setup) {
6836 wl->rfkill = rfkill_alloc("brcmfmac-wifi",
6837 &wl_cfg80211_get_sdio_func()->dev,
6838 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
6839
6840 if (!wl->rfkill) {
6841 err = -ENOMEM;
6842 goto err_out;
6843 }
6844
6845 err = rfkill_register(wl->rfkill);
6846
6847 if (err)
6848 rfkill_destroy(wl->rfkill);
6849 } else {
6850 if (!wl->rfkill) {
6851 err = -ENOMEM;
6852 goto err_out;
6853 }
6854
6855 rfkill_unregister(wl->rfkill);
6856 rfkill_destroy(wl->rfkill);
6857 }
6858
6859err_out:
6860 return err;
6861}
6862
6863#if defined(COEX_DHCP)
6864/*
6865 * get named driver variable to uint register value and return error indication
6866 * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
6867 */
6868static int
6869dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
6870 uint reg, int *retval)
6871{
6872 union {
6873 char buf[WLC_IOCTL_SMLEN];
6874 int val;
6875 } var;
6876 int error;
6877
6878 bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
6879 (char *)(&var), sizeof(var.buf));
6880 error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
6881
6882 *retval = dtoh32(var.val);
6883 return (error);
6884}
6885
6886static int
6887dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
6888{
6889#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
6890 char ioctlbuf[1024];
6891#else
6892 static char ioctlbuf[1024];
6893#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
6894
6895 bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
6896
6897 return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
6898}
6899/*
6900get named driver variable to uint register value and return error indication
6901calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
6902*/
6903static int
6904dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
6905{
6906 char reg_addr[8];
6907
6908 memset(reg_addr, 0, sizeof(reg_addr));
6909 memcpy((char *)&reg_addr[0], (char *)addr, 4);
6910 memcpy((char *)&reg_addr[4], (char *)val, 4);
6911
6912 return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
6913}
6914
6915static bool btcoex_is_sco_active(struct net_device *dev)
6916{
6917 int ioc_res = 0;
6918 bool res = FALSE;
6919 int sco_id_cnt = 0;
6920 int param27;
6921 int i;
6922
6923 for (i = 0; i < 12; i++) {
6924
6925 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
6926
6927 WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
6928 __FUNCTION__, i, param27));
6929
6930 if (ioc_res < 0) {
6931 WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
6932 break;
6933 }
6934
6935 if ((param27 & 0x6) == 2) { /* count both sco & esco */
6936 sco_id_cnt++;
6937 }
6938
6939 if (sco_id_cnt > 2) {
6940 WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
6941 __FUNCTION__, sco_id_cnt, i));
6942 res = TRUE;
6943 break;
6944 }
6945
6946 msleep(5);
6947 }
6948
6949 return res;
6950}
6951
6952#if defined(BT_DHCP_eSCO_FIX)
6953/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
6954static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
6955{
6956 static bool saved_status = FALSE;
6957
6958 char buf_reg50va_dhcp_on[8] =
6959 { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
6960 char buf_reg51va_dhcp_on[8] =
6961 { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6962 char buf_reg64va_dhcp_on[8] =
6963 { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6964 char buf_reg65va_dhcp_on[8] =
6965 { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6966 char buf_reg71va_dhcp_on[8] =
6967 { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6968 uint32 regaddr;
6969 static uint32 saved_reg50;
6970 static uint32 saved_reg51;
6971 static uint32 saved_reg64;
6972 static uint32 saved_reg65;
6973 static uint32 saved_reg71;
6974
6975 if (trump_sco) {
6976 /* this should reduce eSCO agressive retransmit
6977 * w/o breaking it
6978 */
6979
6980 /* 1st save current */
6981 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
6982 "override}\n"));
6983 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
6984 (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
6985 (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
6986 (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
6987 (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
6988 saved_status = TRUE;
6989 WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
6990 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
6991 __FUNCTION__, saved_reg50, saved_reg51,
6992 saved_reg64, saved_reg65, saved_reg71));
6993 } else {
6994 WL_ERR((":%s: save btc_params failed\n",
6995 __FUNCTION__));
6996 saved_status = FALSE;
6997 return -1;
6998 }
6999
7000 WL_TRACE(("override with [50,51,64,65,71]:"
7001 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
7002 *(u32 *)(buf_reg50va_dhcp_on+4),
7003 *(u32 *)(buf_reg51va_dhcp_on+4),
7004 *(u32 *)(buf_reg64va_dhcp_on+4),
7005 *(u32 *)(buf_reg65va_dhcp_on+4),
7006 *(u32 *)(buf_reg71va_dhcp_on+4)));
7007
7008 dev_wlc_bufvar_set(dev, "btc_params",
7009 (char *)&buf_reg50va_dhcp_on[0], 8);
7010 dev_wlc_bufvar_set(dev, "btc_params",
7011 (char *)&buf_reg51va_dhcp_on[0], 8);
7012 dev_wlc_bufvar_set(dev, "btc_params",
7013 (char *)&buf_reg64va_dhcp_on[0], 8);
7014 dev_wlc_bufvar_set(dev, "btc_params",
7015 (char *)&buf_reg65va_dhcp_on[0], 8);
7016 dev_wlc_bufvar_set(dev, "btc_params",
7017 (char *)&buf_reg71va_dhcp_on[0], 8);
7018
7019 saved_status = TRUE;
7020 } else if (saved_status) {
7021 /* restore previously saved bt params */
7022 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
7023 "override}\n"));
7024
7025 regaddr = 50;
7026 dev_wlc_intvar_set_reg(dev, "btc_params",
7027 (char *)&regaddr, (char *)&saved_reg50);
7028 regaddr = 51;
7029 dev_wlc_intvar_set_reg(dev, "btc_params",
7030 (char *)&regaddr, (char *)&saved_reg51);
7031 regaddr = 64;
7032 dev_wlc_intvar_set_reg(dev, "btc_params",
7033 (char *)&regaddr, (char *)&saved_reg64);
7034 regaddr = 65;
7035 dev_wlc_intvar_set_reg(dev, "btc_params",
7036 (char *)&regaddr, (char *)&saved_reg65);
7037 regaddr = 71;
7038 dev_wlc_intvar_set_reg(dev, "btc_params",
7039 (char *)&regaddr, (char *)&saved_reg71);
7040
7041 WL_TRACE(("restore bt_params[50,51,64,65,71]:"
7042 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
7043 saved_reg50, saved_reg51, saved_reg64,
7044 saved_reg65, saved_reg71));
7045
7046 saved_status = FALSE;
7047 } else {
7048 WL_ERR((":%s att to restore not saved BTCOEX params\n",
7049 __FUNCTION__));
7050 return -1;
7051 }
7052 return 0;
7053}
7054#endif /* BT_DHCP_eSCO_FIX */
7055
7056static void
7057wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
7058{
7059#if defined(BT_DHCP_USE_FLAGS)
7060 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
7061 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
7062#endif
7063
7064#if defined(BT_DHCP_eSCO_FIX)
7065 /* set = 1, save & turn on 0 - off & restore prev settings */
7066 set_btc_esco_params(dev, set);
7067#endif
7068
7069#if defined(BT_DHCP_USE_FLAGS)
7070 WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
7071 if (set == TRUE)
7072 /* Forcing bt_flag7 */
7073 dev_wlc_bufvar_set(dev, "btc_flags",
7074 (char *)&buf_flag7_dhcp_on[0],
7075 sizeof(buf_flag7_dhcp_on));
7076 else
7077 /* Restoring default bt flag7 */
7078 dev_wlc_bufvar_set(dev, "btc_flags",
7079 (char *)&buf_flag7_default[0],
7080 sizeof(buf_flag7_default));
7081#endif
7082}
7083
7084static void wl_cfg80211_bt_timerfunc(ulong data)
7085{
7086 struct btcoex_info *bt_local = (struct btcoex_info *)data;
7087 WL_TRACE(("%s\n", __FUNCTION__));
7088 bt_local->timer_on = 0;
7089 schedule_work(&bt_local->work);
7090}
7091
7092static void wl_cfg80211_bt_handler(struct work_struct *work)
7093{
7094 struct btcoex_info *btcx_inf;
7095
7096 btcx_inf = container_of(work, struct btcoex_info, work);
7097
7098 if (btcx_inf->timer_on) {
7099 btcx_inf->timer_on = 0;
7100 del_timer_sync(&btcx_inf->timer);
7101 }
7102
7103 switch (btcx_inf->bt_state) {
7104 case BT_DHCP_START:
7105 /* DHCP started
7106 * provide OPPORTUNITY window to get DHCP address
7107 */
7108 WL_TRACE(("%s bt_dhcp stm: started \n",
7109 __FUNCTION__));
7110 btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
7111 mod_timer(&btcx_inf->timer,
7112 jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
7113 btcx_inf->timer_on = 1;
7114 break;
7115
7116 case BT_DHCP_OPPR_WIN:
7117 if (btcx_inf->dhcp_done) {
7118 WL_TRACE(("%s DHCP Done before T1 expiration\n",
7119 __FUNCTION__));
7120 goto btc_coex_idle;
7121 }
7122
7123 /* DHCP is not over yet, start lowering BT priority
7124 * enforce btc_params + flags if necessary
7125 */
7126 WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
7127 BT_DHCP_OPPR_WIN_TIME));
7128 if (btcx_inf->dev)
7129 wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
7130 btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
7131 mod_timer(&btcx_inf->timer,
7132 jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
7133 btcx_inf->timer_on = 1;
7134 break;
7135
7136 case BT_DHCP_FLAG_FORCE_TIMEOUT:
7137 if (btcx_inf->dhcp_done) {
7138 WL_TRACE(("%s DHCP Done before T2 expiration\n",
7139 __FUNCTION__));
7140 } else {
7141 /* Noo dhcp during T1+T2, restore BT priority */
7142 WL_TRACE(("%s DHCP wait interval T2:%d"
7143 "msec expired\n", __FUNCTION__,
7144 BT_DHCP_FLAG_FORCE_TIME));
7145 }
7146
7147 /* Restoring default bt priority */
7148 if (btcx_inf->dev)
7149 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
7150btc_coex_idle:
7151 btcx_inf->bt_state = BT_DHCP_IDLE;
7152 btcx_inf->timer_on = 0;
7153 break;
7154
7155 default:
7156 WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
7157 btcx_inf->bt_state));
7158 if (btcx_inf->dev)
7159 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
7160 btcx_inf->bt_state = BT_DHCP_IDLE;
7161 btcx_inf->timer_on = 0;
7162 break;
7163 }
7164
7165 net_os_wake_unlock(btcx_inf->dev);
7166}
7167
7168static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
7169{
7170 struct btcoex_info *btco_inf = NULL;
7171
7172 btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
7173 if (!btco_inf)
7174 return -ENOMEM;
7175
7176 btco_inf->bt_state = BT_DHCP_IDLE;
7177 btco_inf->ts_dhcp_start = 0;
7178 btco_inf->ts_dhcp_ok = 0;
7179 /* Set up timer for BT */
7180 btco_inf->timer_ms = 10;
7181 init_timer(&btco_inf->timer);
7182 btco_inf->timer.data = (ulong)btco_inf;
7183 btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
7184
7185 btco_inf->dev = wl->wdev->netdev;
7186
7187 INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
7188
7189 wl->btcoex_info = btco_inf;
7190 return 0;
7191}
7192
7193static void
7194wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
7195{
7196 if (!wl->btcoex_info)
7197 return;
7198
7199 if (!wl->btcoex_info->timer_on) {
7200 wl->btcoex_info->timer_on = 0;
7201 del_timer_sync(&wl->btcoex_info->timer);
7202 }
7203
7204 cancel_work_sync(&wl->btcoex_info->work);
7205
7206 kfree(wl->btcoex_info);
7207 wl->btcoex_info = NULL;
7208}
7209#endif /* COEX_DHCP */
7210
7211int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
7212{
7213 char powermode_val = 0;
7214 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
7215 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
7216 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
7217
7218 uint32 regaddr;
7219 static uint32 saved_reg66;
7220 static uint32 saved_reg41;
7221 static uint32 saved_reg68;
7222 static bool saved_status = FALSE;
7223
7224#ifdef COEX_DHCP
7225 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
7226 struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
7227#endif /* COEX_DHCP */
7228
7229 /* Figure out powermode 1 or o command */
7230 strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
7231
7232 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
7233
7234 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
7235
7236 /* Retrieve and saved orig regs value */
7237 if ((saved_status == FALSE) &&
7238 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
7239 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
7240 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
7241 saved_status = TRUE;
7242 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
7243 saved_reg66, saved_reg41, saved_reg68));
7244
7245 /* Disable PM mode during dhpc session */
7246
7247 /* Disable PM mode during dhpc session */
7248#ifdef COEX_DHCP
7249 /* Start BT timer only for SCO connection */
7250 if (btcoex_is_sco_active(dev)) {
7251 /* btc_params 66 */
7252 dev_wlc_bufvar_set(dev, "btc_params",
7253 (char *)&buf_reg66va_dhcp_on[0],
7254 sizeof(buf_reg66va_dhcp_on));
7255 /* btc_params 41 0x33 */
7256 dev_wlc_bufvar_set(dev, "btc_params",
7257 (char *)&buf_reg41va_dhcp_on[0],
7258 sizeof(buf_reg41va_dhcp_on));
7259 /* btc_params 68 0x190 */
7260 dev_wlc_bufvar_set(dev, "btc_params",
7261 (char *)&buf_reg68va_dhcp_on[0],
7262 sizeof(buf_reg68va_dhcp_on));
7263 saved_status = TRUE;
7264
7265 btco_inf->bt_state = BT_DHCP_START;
7266 btco_inf->timer_on = 1;
7267 mod_timer(&btco_inf->timer, btco_inf->timer.expires);
7268 WL_TRACE(("%s enable BT DHCP Timer\n",
7269 __FUNCTION__));
7270 }
7271#endif /* COEX_DHCP */
7272 }
7273 else if (saved_status == TRUE) {
7274 WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
7275 }
7276 }
7277 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
7278
7279
7280 /* Restoring PM mode */
7281
7282#ifdef COEX_DHCP
7283 /* Stop any bt timer because DHCP session is done */
7284 WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
7285 if (btco_inf->timer_on) {
7286 btco_inf->timer_on = 0;
7287 del_timer_sync(&btco_inf->timer);
7288
7289 if (btco_inf->bt_state != BT_DHCP_IDLE) {
7290 /* need to restore original btc flags & extra btc params */
7291 WL_TRACE(("%s bt->bt_state:%d\n",
7292 __FUNCTION__, btco_inf->bt_state));
7293 /* wake up btcoex thread to restore btlags+params */
7294 schedule_work(&btco_inf->work);
7295 }
7296 }
7297
7298 /* Restoring btc_flag paramter anyway */
7299 if (saved_status == TRUE)
7300 dev_wlc_bufvar_set(dev, "btc_flags",
7301 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
7302#endif /* COEX_DHCP */
7303
7304 /* Restore original values */
7305 if (saved_status == TRUE) {
7306 regaddr = 66;
7307 dev_wlc_intvar_set_reg(dev, "btc_params",
7308 (char *)&regaddr, (char *)&saved_reg66);
7309 regaddr = 41;
7310 dev_wlc_intvar_set_reg(dev, "btc_params",
7311 (char *)&regaddr, (char *)&saved_reg41);
7312 regaddr = 68;
7313 dev_wlc_intvar_set_reg(dev, "btc_params",
7314 (char *)&regaddr, (char *)&saved_reg68);
7315
7316 WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
7317 saved_reg66, saved_reg41, saved_reg68));
7318 }
7319 saved_status = FALSE;
7320
7321 }
7322 else {
7323 WL_ERR(("%s Unkwown yet power setting, ignored\n",
7324 __FUNCTION__));
7325 }
7326
7327 snprintf(command, 3, "OK");
7328
7329 return (strlen("OK"));
7330}