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