summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/bcmdhd/wl_cfg80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c3698
1 files changed, 1827 insertions, 1871 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 04affb50b18b..f728c14622a1 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -2,13 +2,13 @@
* Linux cfg80211 driver
*
* Copyright (C) 1999-2011, Broadcom Corporation
- *
+ *
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
- *
+ *
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -41,10 +41,9 @@
#include <dhd.h>
#include <dhdioctl.h>
#include <wlioctl.h>
+#include <dhd_cfg80211.h>
#include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
@@ -54,54 +53,29 @@
#include <linux/ieee80211.h>
#include <linux/wait.h>
#include <net/cfg80211.h>
-
#include <net/rtnetlink.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/firmware.h>
-#include <bcmsdbus.h>
#include <wlioctl.h>
#include <wldev_common.h>
#include <wl_cfg80211.h>
#include <wl_cfgp2p.h>
-static struct sdio_func *cfg80211_sdio_func;
-static struct wl_priv *wlcfg_drv_priv;
+static struct device *cfg80211_parent_dev = NULL;
+static int vsdb_supported = 0;
+struct wl_priv *wlcfg_drv_priv = NULL;
u32 wl_dbg_level = WL_DBG_ERR;
-#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
-#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAX_WAIT_TIME 1500
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
+#define WL_SCAN_ACTIVE_TIME 40
+#define WL_SCAN_PASSIVE_TIME 130
+#define WL_FRAME_LEN 300
+#define DNGL_FUNC(func, parameters) func parameters;
#define COEX_DHCP
-#if defined(COEX_DHCP)
-#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG
- * suppression
- */
-#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority
- * to max, caution: -not fair to sco
- */
-#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority
- * suppression
- */
-#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion
- * is (timeout)
- */
-enum wl_cfg80211_btcoex_status {
- BT_DHCP_IDLE,
- BT_DHCP_START,
- BT_DHCP_OPPR_WIN,
- BT_DHCP_FLAG_FORCE_TIMEOUT
-};
-
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
-static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
-#endif
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
@@ -121,8 +95,10 @@ static const struct ieee80211_regdomain brcm_regdom = {
REG_RULE(2467-10, 2472+10, 20, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
- /* IEEE 802.11 channel 14 - Only JP enables
- * this and for 802.11b only
+ /*
+ * IEEE 802.11 channel 14 - is for JP only,
+ * we need cfg80211 to allow it (reg_flags = 0); so that
+ * hostapd could request auto channel by sending down ch 14
*/
REG_RULE(2484-10, 2484+10, 20, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
@@ -224,7 +200,8 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa);
static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
struct net_device *dev);
-static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted);
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
+ struct net_device *ndev, bool aborted, bool fw_abort);
/*
* event & event Q handlers for cfg80211 interfaces
*/
@@ -242,6 +219,8 @@ static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type,
const wl_event_msg_t *msg, void *data);
static void wl_put_event(struct wl_event_q *e);
static void wl_wakeup_event(struct wl_priv *wl);
+static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
static s32 wl_notify_connect_status(struct wl_priv *wl,
struct net_device *ndev,
const wl_event_msg_t *e, void *data);
@@ -256,22 +235,19 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
+#ifdef WL_SCHED_SCAN
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WL_SCHED_SCAN */
+#ifdef PNO_SUPPORT
+static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* PNO_SUPPORT */
/*
- * register/deregister sdio function
- */
-struct sdio_func *wl_cfg80211_get_sdio_func(void);
-static void wl_clear_sdio_func(void);
-
-/*
- * ioctl utilites
+ * register/deregister parent device
*/
-static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
- s32 buf_len);
-static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
- s8 *buf, s32 len);
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
-static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
- s32 *retval);
+static void wl_cfg80211_clear_parent_dev(void);
/*
* cfg80211 set_wiphy_params utilities
@@ -283,10 +259,10 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
/*
* wl profile utilities
*/
-static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
- void *data, s32 item);
-static void *wl_read_prof(struct wl_priv *wl, s32 item);
-static void wl_init_prof(struct wl_priv *wl);
+static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, s32 item);
+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item);
+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev);
/*
* cfg80211 connect utilites
@@ -314,14 +290,14 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
static u32 wl_get_ielen(struct wl_priv *wl);
-static s32 wl_mode_to_nl80211_iftype(s32 mode);
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev);
static void wl_free_wdev(struct wl_priv *wl);
static s32 wl_inform_bss(struct wl_priv *wl);
static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr,
@@ -347,42 +323,19 @@ static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev);
static __used bool wl_is_ibssstarter(struct wl_priv *wl);
/*
- * dongle up/down , default configuration utilities
+ * link up/down , default configuration utilities
*/
+static s32 __wl_cfg80211_up(struct wl_priv *wl);
+static s32 __wl_cfg80211_down(struct wl_priv *wl);
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev);
static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
static void wl_link_up(struct wl_priv *wl);
static void wl_link_down(struct wl_priv *wl);
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
-static s32 __wl_cfg80211_up(struct wl_priv *wl);
-static s32 __wl_cfg80211_down(struct wl_priv *wl);
-static s32 wl_dongle_probecap(struct wl_priv *wl);
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
static void wl_init_conf(struct wl_conf *conf);
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
-
-/*
- * dongle configuration utilities
- */
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
-static s32 wl_dongle_up(struct net_device *ndev, u32 up);
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
-static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
- u32 dongle_align);
-static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
- u32 bcn_timeout);
-static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time);
-static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
- s32 arp_ol);
-static s32 wl_pattern_atoh(s8 *src, s8 *dst);
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
static s32 wl_update_wiphybands(struct wl_priv *wl);
-#endif /* !EMBEDDED_PLATFORM */
-static __used void wl_dongle_poweron(struct wl_priv *wl);
-static __used void wl_dongle_poweroff(struct wl_priv *wl);
-static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
/*
* iscan handler
@@ -406,33 +359,20 @@ static s32 wl_iscan_inprogress(struct wl_priv *wl);
static s32 wl_iscan_aborted(struct wl_priv *wl);
/*
- * fw/nvram downloading handler
- */
-static void wl_init_fw(struct wl_fw_ctrl *fw);
-
-/*
* find most significant bit set
*/
static __used u32 wl_find_msb(u16 bit16);
/*
- * update pmklist to dongle
- */
-static __used s32 wl_update_pmklist(struct net_device *dev,
- struct wl_pmk_list *pmk_list, s32 err);
-
-/*
- * debufs support
- */
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl);
-static void wl_debugfs_remove_netdev(struct wl_priv *wl);
-
-/*
* rfkill support
*/
static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
static int wl_rfkill_set(void *data, bool blocked);
+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel,
+ int nprobes, int *out_params_size);
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac);
+
/*
* Some external functions, TODO: move them to dhd_linux.h
*/
@@ -444,10 +384,10 @@ int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
#define CHECK_SYS_UP(wlpriv) \
do { \
- if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \
- WL_INFO(("device is not ready : status (%d)\n", \
- (int)wlpriv->status)); \
- return -EIO; \
+ struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \
+ if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \
+ WL_INFO(("device is not ready\n")); \
+ return -EIO; \
} \
} while (0)
@@ -740,6 +680,43 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc)
}
}
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+{
+ if (vsdb_supported) {
+ return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ }
+ else {
+ chanspec_t chspec;
+ int err = 0;
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ struct net_device *dev = wl_to_prmry_ndev(wl);
+ struct ether_addr bssid;
+ struct wl_bss_info *bss = NULL;
+ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
+ /* STA interface is not associated. So start the new interface on a temp
+ * channel . Later proper channel will be applied by the above framework
+ * via set_channel (cfg80211 API).
+ */
+ WL_DBG(("Not associated. Return a temp channel. \n"));
+ return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ }
+
+
+ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
+ sizeof(WL_EXTRA_BUF_MAX), false))) {
+ WL_ERR(("Failed to get associated bss info, use temp channel \n"));
+ chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ }
+ else {
+ bss = (struct wl_bss_info *) (wl->extra_buf + 4);
+ chspec = bss->chanspec;
+ WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec));
+ }
+ return chspec;
+ }
+}
+
static struct net_device* wl_cfg80211_add_monitor_if(char *name)
{
int ret = 0;
@@ -758,15 +735,20 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
s32 err;
s32 timeout = -1;
s32 wlif_type = -1;
- s32 index = 0;
s32 mode = 0;
+#if defined(WL_ENABLE_P2P_IF)
+ s32 dhd_mode = 0;
+#endif /* (WL_ENABLE_P2P_IF) */
chanspec_t chspec;
struct wl_priv *wl = wiphy_priv(wiphy);
struct net_device *_ndev;
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
- int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
+ struct ether_addr primary_mac;
+ int (*net_attach)(void *dhdp, int ifidx);
bool rollback_lock = false;
+ /* Use primary I/F for sending cmds down to firmware */
+ _ndev = wl_to_prmry_ndev(wl);
+
WL_DBG(("if name: %s, type: %d\n", name, type));
switch (type) {
case NL80211_IFTYPE_ADHOC:
@@ -798,6 +780,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
WL_ERR(("name is NULL\n"));
return NULL;
}
+ if (wl->iface_cnt == IFACE_MAX_CNT)
+ return ERR_PTR(-ENOMEM);
if (wl->p2p_supported && (wlif_type != -1)) {
if (wl_get_p2p_status(wl, IF_DELETING)) {
/* wait till IF_DEL is complete
@@ -809,7 +793,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
}
WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
__func__));
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, IF_DELETING) == false),
msecs_to_jiffies(MAX_WAIT_TIME));
@@ -826,17 +810,25 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
return ERR_PTR(-EAGAIN);
}
}
- if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
p2p_on(wl) = true;
wl_cfgp2p_set_firm_p2p(wl);
wl_cfgp2p_init_discovery(wl);
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &wl->p2p->dev_addr, &wl->p2p->int_addr);
}
+
memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
- /* Temporary use channel 11, in case GO will be changed with set_channel API */
- chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ wldev_iovar_setint(_ndev, "mpc", 0);
+ wl_notify_escan_complete(wl, _ndev, true, true);
+ /* In concurrency case, STA may be already associated in a particular channel.
+ * so retrieve the current channel of primary interface and then start the virtual
+ * interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
/* For P2P mode, use P2P-specific driver features to create the
* bss: "wl p2p_ifadd"
@@ -844,10 +836,12 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
wl_set_p2p_status(wl, IF_ADD);
err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR((" virtual iface add failed (%d) \n", err));
return ERR_PTR(-ENOMEM);
+ }
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, IF_ADD) == false),
msecs_to_jiffies(MAX_WAIT_TIME));
if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
@@ -860,27 +854,37 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
}
vwdev->wiphy = wl->wdev->wiphy;
WL_INFO((" virtual interface(%s) is created memalloc done \n",
- wl->p2p->vir_ifname));
- index = alloc_idx_vwdev(wl);
- wl->vwdev[index] = vwdev;
- vwdev->iftype =
- (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
- : NL80211_IFTYPE_AP;
+ wl->p2p->vir_ifname));
+ vwdev->iftype = type;
_ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
_ndev->ieee80211_ptr = vwdev;
SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
vwdev->netdev = _ndev;
- wl_set_drv_status(wl, READY);
+ wl_set_drv_status(wl, READY, _ndev);
wl->p2p->vif_created = true;
- set_mode_by_netdev(wl, _ndev, mode);
+ wl_set_mode_by_netdev(wl, _ndev, mode);
net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
if (rtnl_is_locked()) {
rtnl_unlock();
rollback_lock = true;
}
- if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
- WL_DBG((" virtual interface(%s) is "
+ if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) {
+ wl_alloc_netinfo(wl, _ndev, vwdev, mode);
+ WL_ERR((" virtual interface(%s) is "
"created net attach done\n", wl->p2p->vir_ifname));
+#if defined(WL_ENABLE_P2P_IF)
+ if (type == NL80211_IFTYPE_P2P_CLIENT)
+ dhd_mode = P2P_GC_ENABLED;
+ else if (type == NL80211_IFTYPE_P2P_GO)
+ dhd_mode = P2P_GO_ENABLED;
+ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode));
+#endif /* (WL_ENABLE_P2P_IF) */
+ /* Start the P2P I/F with PM disabled. Enable PM from
+ * the framework
+ */
+ if ((type == NL80211_IFTYPE_P2P_CLIENT) || (
+ type == NL80211_IFTYPE_P2P_GO))
+ vwdev->ps = NL80211_PS_DISABLED;
} else {
/* put back the rtnl_lock again */
if (rollback_lock)
@@ -911,34 +915,46 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
s32 timeout = -1;
s32 ret = 0;
WL_DBG(("Enter\n"));
+
+ if (wl->p2p_net == dev) {
+ /* Since there is no ifidx corresponding to p2p0, cmds to
+ * firmware should be routed through primary I/F
+ */
+ dev = wl_to_prmry_ndev(wl);
+ }
+
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
if (wl->p2p->vif_created) {
- if (wl_get_drv_status(wl, SCANNING)) {
- wl_cfg80211_scan_abort(wl, dev);
+ if (wl_get_drv_status(wl, SCANNING, dev)) {
+ wl_notify_escan_complete(wl, dev, true, true);
}
wldev_iovar_setint(dev, "mpc", 1);
wl_set_p2p_status(wl, IF_DELETING);
ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
- if (ret) {
/* Firmware could not delete the interface so we will not get WLC_E_IF
* event for cleaning the dhd virtual nw interace
* So lets do it here. Failures from fw will ensure the application to do
* ifconfig <inter> down and up sequnce, which will reload the fw
* however we should cleanup the linux network virtual interfaces
*/
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
- WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
- WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
- dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
+ /* Request framework to RESET and clean up */
+ if (ret) {
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+ WL_ERR(("Firmware returned an error (%d) from p2p_ifdel"
+ "HANG Notification sent to %s\n", ret, ndev->name));
+ wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED);
}
/* Wait for any pending scan req to get aborted from the sysioc context */
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl_get_p2p_status(wl, IF_DELETING) == false),
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
+ (wl->p2p->vif_created == false),
msecs_to_jiffies(MAX_WAIT_TIME));
- if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
+ if (timeout > 0 && (wl->p2p->vif_created == false)) {
WL_DBG(("IFDEL operation done\n"));
+#if defined(WL_ENABLE_P2P_IF)
+ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl));
+#endif /* (WL_ENABLE_P2P_IF)) */
} else {
WL_ERR(("IFDEL didn't complete properly\n"));
}
@@ -961,7 +977,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
s32 mode = 0;
chanspec_t chspec;
struct wl_priv *wl = wiphy_priv(wiphy);
- WL_DBG(("Enter \n"));
+
+ WL_DBG(("Enter type %d\n", type));
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
@@ -988,28 +1005,35 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
return -EINVAL;
}
-
if (ap) {
- set_mode_by_netdev(wl, ndev, mode);
+ wl_set_mode_by_netdev(wl, ndev, mode);
if (wl->p2p_supported && wl->p2p->vif_created) {
WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
- p2p_on(wl)));
- chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ p2p_on(wl)));
+ wldev_iovar_setint(ndev, "mpc", 0);
+ wl_notify_escan_complete(wl, ndev, true, true);
+
+ /* In concurrency case, STA may be already associated in a particular
+ * channel. so retrieve the current channel of primary interface and
+ * then start the virtual interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
ndev->name, ap, infra, type));
wl_set_p2p_status(wl, IF_CHANGING);
wl_clr_p2p_status(wl, IF_CHANGED);
err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, IF_CHANGED) == true),
msecs_to_jiffies(MAX_WAIT_TIME));
- set_mode_by_netdev(wl, ndev, mode);
+ wl_set_mode_by_netdev(wl, ndev, mode);
wl_clr_p2p_status(wl, IF_CHANGING);
wl_clr_p2p_status(wl, IF_CHANGED);
} else if (ndev == wl_to_prmry_ndev(wl) &&
- !wl_get_drv_status(wl, AP_CREATED)) {
- wl_set_drv_status(wl, AP_CREATING);
+ !wl_get_drv_status(wl, AP_CREATED, ndev)) {
+ wl_set_drv_status(wl, AP_CREATING, ndev);
if (!wl->ap_info &&
!(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
WL_ERR(("struct ap_saved_ie allocation failed\n"));
@@ -1027,15 +1051,16 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
s32
wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
+ void* _net_attach)
{
struct wl_priv *wl = wlcfg_drv_priv;
s32 ret = BCME_OK;
+ WL_DBG(("Enter"));
if (!ndev) {
WL_ERR(("net is NULL\n"));
return 0;
}
- if (wl->p2p_supported) {
+ if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) {
WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
"new name: %s\n", ndev->name, wl->p2p->vir_ifname));
/* Assign the net device to CONNECT BSSCFG */
@@ -1046,13 +1071,26 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
ndev->ifindex = idx;
wl_clr_p2p_status(wl, IF_ADD);
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->netif_change_event);
+ } else {
+ ret = BCME_NOTREADY;
}
return ret;
}
s32
-wl_cfg80211_notify_ifdel(struct net_device *ndev)
+wl_cfg80211_notify_ifdel(void)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ WL_DBG(("Enter \n"));
+ wl_clr_p2p_status(wl, IF_DELETING);
+
+ return 0;
+}
+
+s32
+wl_cfg80211_ifdel_ops(struct net_device *ndev)
{
struct wl_priv *wl = wlcfg_drv_priv;
bool rollback_lock = false;
@@ -1063,8 +1101,10 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
return 0;
}
- if (p2p_is_on(wl) && wl->p2p->vif_created) {
- if (wl->scan_request) {
+ if (p2p_is_on(wl) && wl->p2p->vif_created &&
+ wl_get_p2p_status(wl, IF_DELETING)) {
+ if (wl->scan_request &&
+ (wl->escan_info.ndev == ndev)) {
/* Abort any pending scan requests */
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (!rtnl_is_locked()) {
@@ -1072,7 +1112,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
rollback_lock = true;
}
WL_DBG(("ESCAN COMPLETED\n"));
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
if (rollback_lock)
rtnl_unlock();
}
@@ -1086,12 +1126,12 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
wl->p2p->vif_created = false;
wl_cfgp2p_clear_management_ie(wl,
index);
- wl_clr_p2p_status(wl, IF_DELETING);
WL_DBG(("index : %d\n", index));
}
+
/* Wake up any waiting thread */
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->netif_change_event);
return 0;
}
@@ -1123,15 +1163,15 @@ wl_cfg80211_notify_ifchange(void)
struct wl_priv *wl = wlcfg_drv_priv;
if (wl_get_p2p_status(wl, IF_CHANGING)) {
wl_set_p2p_status(wl, IF_CHANGED);
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->netif_change_event);
}
return 0;
}
static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
{
- u32 n_ssids = request->n_ssids;
- u32 n_channels = request->n_channels;
+ u32 n_ssids;
+ u32 n_channels;
u16 channel;
chanspec_t chanspec;
s32 i, offset;
@@ -1160,6 +1200,13 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
params->passive_time = htod32(params->passive_time);
params->home_time = htod32(params->home_time);
+ /* if request is null just exit so it will be all channel broadcast scan */
+ if (!request)
+ return;
+
+ n_ssids = request->n_ssids;
+ n_channels = request->n_channels;
+
/* Copy channel array if applicable */
WL_SCAN(("### List of channelspecs to scan ###\n"));
if (n_channels > 0) {
@@ -1186,7 +1233,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK;
params->channel_list[i] |= chanspec;
WL_SCAN(("Chan : %d, Channel spec: %x \n",
- channel, params->channel_list[i]));
+ channel, params->channel_list[i]));
params->channel_list[i] = htod16(params->channel_list[i]);
}
} else {
@@ -1248,8 +1295,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
return -ENOMEM;
}
- if (request != NULL)
- wl_scan_prep(&params->params, request);
+ wl_scan_prep(&params->params, request);
params->version = htod32(ISCAN_REQ_VERSION);
params->action = htod16(action);
@@ -1261,7 +1307,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
goto done;
}
err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
- iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
+ iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
if (unlikely(err)) {
if (err == -EBUSY) {
WL_ERR(("system busy : iscan canceled\n"));
@@ -1299,6 +1345,25 @@ static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request
}
static s32
+wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
+{
+ wl_uint32_list_t *list;
+ s32 err = BCME_OK;
+ if (valid_chan_list == NULL || size <= 0)
+ return -ENOMEM;
+
+ memset(valid_chan_list, 0, size);
+ list = (wl_uint32_list_t *)(void *) valid_chan_list;
+ list->count = htod32(WL_NUMCHANNELS);
+ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false);
+ if (err != 0) {
+ WL_ERR(("get channels failed with %d\n", err));
+ }
+
+ return err;
+}
+
+static s32
wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
struct cfg80211_scan_request *request, uint16 action)
{
@@ -1306,12 +1371,16 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
u32 n_channels;
u32 n_ssids;
s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
- wl_escan_params_t *params;
+ wl_escan_params_t *params = NULL;
struct cfg80211_scan_request *scan_request = wl->scan_request;
+ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
u32 num_chans = 0;
+ s32 channel;
+ s32 n_valid_chan;
s32 search_state = WL_P2P_DISC_ST_SCAN;
- u32 i;
+ u32 i, j, n_nodfs = 0;
u16 *default_chan_list = NULL;
+ wl_uint32_list_t *list;
struct net_device *dev = NULL;
WL_DBG(("Enter \n"));
@@ -1340,8 +1409,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
goto exit;
}
- if (request != NULL)
- wl_scan_prep(&params->params, request);
+ wl_scan_prep(&params->params, request);
params->version = htod32(ESCAN_REQ_VERSION);
params->action = htod16(action);
params->sync_id = htod16(0x1234);
@@ -1352,13 +1420,15 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
goto exit;
}
err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
- wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
+ wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
if (unlikely(err))
WL_ERR((" Escan set error (%d)\n", err));
kfree(params);
}
- else if (p2p_on(wl) && p2p_scan(wl)) {
+ else if (p2p_is_on(wl) && p2p_scan(wl)) {
/* P2P SCAN TRIGGER */
+ s32 _freq = 0;
+ n_nodfs = 0;
if (scan_request && scan_request->n_channels) {
num_chans = scan_request->n_channels;
WL_SCAN((" chann number : %d\n", num_chans));
@@ -1369,11 +1439,26 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
err = -ENOMEM;
goto exit;
}
- for (i = 0; i < num_chans; i++)
- {
- default_chan_list[i] =
- ieee80211_frequency_to_channel(
- scan_request->channels[i]->center_freq);
+ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
+ list = (wl_uint32_list_t *) chan_buf;
+ n_valid_chan = dtoh32(list->count);
+ for (i = 0; i < num_chans; i++)
+ {
+ _freq = scan_request->channels[i]->center_freq;
+ channel = ieee80211_frequency_to_channel(_freq);
+ /* remove DFS channels */
+ if (channel < 52 || channel > 140) {
+ for (j = 0; j < n_valid_chan; j++) {
+ /* allows only supported channel on
+ * current reguatory
+ */
+ if (channel == (dtoh32(list->element[j])))
+ default_chan_list[n_nodfs++] =
+ channel;
+ }
+ }
+
+ }
}
if (num_chans == 3 && (
(default_chan_list[0] == SOCIAL_CHAN_1) &&
@@ -1383,12 +1468,15 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
search_state = WL_P2P_DISC_ST_SEARCH;
WL_INFO(("P2P SEARCH PHASE START \n"));
} else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) &&
- (get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
+ (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
/* If you are already a GO, then do SEARCH only */
WL_INFO(("Already a GO. Do SEARCH Only"));
search_state = WL_P2P_DISC_ST_SEARCH;
+ num_chans = n_nodfs;
+
} else {
WL_INFO(("P2P SCAN STATE START \n"));
+ num_chans = n_nodfs;
}
}
@@ -1413,7 +1501,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev,
s32 passive_scan;
wl_scan_results_t *results;
WL_SCAN(("Enter \n"));
-
+ wl->escan_info.ndev = ndev;
wl->escan_info.wiphy = wiphy;
wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
passive_scan = wl->active_scan ? 0 : 1;
@@ -1440,36 +1528,41 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_ssid *ssids;
struct wl_scan_req *sr = wl_to_sr(wl);
+ struct ether_addr primary_mac;
wpa_ie_fixed_t *wps_ie;
s32 passive_scan;
bool iscan_req;
- bool escan_req;
- bool spec_scan;
+ bool escan_req = false;
bool p2p_ssid;
s32 err = 0;
s32 i;
u32 wpsie_len = 0;
u8 wpsie[IE_MAX_LEN];
+ /* If scan req comes for p2p0, send it over primary I/F
+ * Scan results will be delivered corresponding to cfg80211_scan_request
+ */
+ if (ndev == wl->p2p_net) {
+ ndev = wl_to_prmry_ndev(wl);
+ }
+
WL_DBG(("Enter wiphy (%p)\n", wiphy));
- if (unlikely(wl_get_drv_status(wl, SCANNING))) {
- WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
+ if (wl_get_drv_status_all(wl, SCANNING)) {
+ WL_ERR(("Scanning already\n"));
return -EAGAIN;
}
- if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) {
- WL_ERR(("Scanning being aborted : status (%d)\n",
- (int)wl->status));
+ if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) {
+ WL_ERR(("Scanning being aborted\n"));
return -EAGAIN;
}
- if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
- WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
+ WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
return -EOPNOTSUPP;
}
/* Arm scan timeout timer */
mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
iscan_req = false;
- spec_scan = false;
if (request) { /* scan bss */
ssids = request->ssids;
if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
@@ -1490,6 +1583,9 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
/* p2p on at the first time */
p2p_on(wl) = true;
wl_cfgp2p_set_firm_p2p(wl);
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &wl->p2p->dev_addr, &wl->p2p->int_addr);
}
p2p_scan(wl) = true;
}
@@ -1543,7 +1639,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
ssids = this_ssid;
}
wl->scan_request = request;
- wl_set_drv_status(wl, SCANNING);
+ wl_set_drv_status(wl, SCANNING, ndev);
if (iscan_req) {
err = wl_do_iscan(wl, request);
if (likely(!err))
@@ -1578,7 +1674,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n",
sr->ssid.SSID, sr->ssid.SSID_len));
- spec_scan = true;
} else {
WL_SCAN(("Broadcast scan\n"));
}
@@ -1606,7 +1701,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
return 0;
scan_out:
- wl_clr_drv_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, ndev);
wl->scan_request = NULL;
return err;
}
@@ -1630,52 +1725,11 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
return err;
}
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
-{
- s8 buf[WLC_IOCTL_SMLEN];
- u32 len;
- s32 err = 0;
-
- val = htod32(val);
- len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
- BUG_ON(unlikely(!len));
-
- err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- }
-
- return err;
-}
-
-static s32
-wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
-{
- union {
- s8 buf[WLC_IOCTL_SMLEN];
- s32 val;
- } var;
- u32 len;
- u32 data_null;
- s32 err = 0;
-
- len = bcm_mkiovar(name, (char *)(&data_null), 0,
- (char *)(&var), sizeof(var.buf));
- BUG_ON(unlikely(!len));
- err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- }
- *retval = dtoh32(var.val);
-
- return err;
-}
-
static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
{
s32 err = 0;
- err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
+ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
@@ -1687,7 +1741,7 @@ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
{
s32 err = 0;
- err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
+ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
@@ -1716,6 +1770,7 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
s32 err = 0;
CHECK_SYS_UP(wl);
+ WL_DBG(("Enter\n"));
if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
(wl->conf->rts_threshold != wiphy->rts_threshold)) {
wl->conf->rts_threshold = wiphy->rts_threshold;
@@ -1745,7 +1800,6 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return err;
}
}
-
return err;
}
@@ -1862,7 +1916,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
WL_ERR(("set wpa_auth failed (%d)\n", err));
return err;
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->wpa_versions = sme->crypto.wpa_versions;
return err;
}
@@ -1877,21 +1931,21 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
switch (sme->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
- val = 0;
+ val = WL_AUTH_OPEN_SYSTEM;
WL_DBG(("open system\n"));
break;
case NL80211_AUTHTYPE_SHARED_KEY:
- val = 1;
+ val = WL_AUTH_SHARED_KEY;
WL_DBG(("shared key\n"));
break;
case NL80211_AUTHTYPE_AUTOMATIC:
- val = 2;
+ val = WL_AUTH_OPEN_SHARED;
WL_DBG(("automatic\n"));
break;
case NL80211_AUTHTYPE_NETWORK_EAP:
WL_DBG(("network eap\n"));
default:
- val = 2;
+ val = WL_AUTH_OPEN_SHARED;
WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
break;
}
@@ -1901,7 +1955,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
WL_ERR(("set auth failed (%d)\n", err));
return err;
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->auth_type = sme->auth_type;
return err;
}
@@ -1962,7 +2016,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
if (is_wps_conn(sme)) {
- err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+ if (sme->privacy)
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+ else
+ /* WPS-2.0 allowes no security */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
} else {
WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
err = wldev_iovar_setint_bsscfg(dev, "wsec",
@@ -1973,7 +2031,7 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
return err;
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
sec->cipher_group = sme->crypto.cipher_group;
@@ -1990,7 +2048,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
if (sme->crypto.n_akm_suites) {
- err = wl_dev_intvar_get(dev, "wpa_auth", &val);
+ err = wldev_iovar_getint(dev, "wpa_auth", &val);
if (unlikely(err)) {
WL_ERR(("could not get wpa_auth (%d)\n", err));
return err;
@@ -2030,7 +2088,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
return err;
}
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->wpa_auth = sme->crypto.akm_suites[0];
return err;
@@ -2049,13 +2107,14 @@ wl_set_set_sharedkey(struct net_device *dev,
WL_DBG(("key len (%d)\n", sme->key_len));
if (sme->key_len) {
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
sec->wpa_versions, sec->cipher_pairwise));
if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
NL80211_WPA_VERSION_2)) &&
(sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
- WLAN_CIPHER_SUITE_WEP104))) {
+ WLAN_CIPHER_SUITE_WEP104)))
+ {
memset(&key, 0, sizeof(key));
key.len = (u32) sme->key_len;
key.index = (u32) sme->key_idx;
@@ -2083,14 +2142,14 @@ wl_set_set_sharedkey(struct net_device *dev,
WL_DBG(("key \"%s\"\n", key.data));
swap_key_from_BE(&key);
err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
- ioctlbuf, sizeof(ioctlbuf), bssidx);
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
}
- if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
WL_DBG(("set auth_type to shared key\n"));
- val = 1; /* shared key */
+ val = WL_AUTH_SHARED_KEY; /* shared key */
err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
if (unlikely(err)) {
WL_ERR(("set auth failed (%d)\n", err));
@@ -2129,15 +2188,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
/* Clean BSSID */
bzero(&bssid, sizeof(bssid));
- wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID);
+ wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
/* we only allow to connect using virtual interface in case of P2P */
- if (p2p_on(wl) && is_wps_conn(sme)) {
+ if (p2p_is_on(wl) && is_wps_conn(sme)) {
WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n",
wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
/* Have to apply WPS IE + P2P IE in assoc req frame */
@@ -2148,7 +2207,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len);
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
- } else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
+ } else if (p2p_is_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
/* This is the connect req after WPS is done [credentials exchanged]
* currently identified with WPA_VERSION_2 .
* Update the previously set IEs with
@@ -2158,6 +2217,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n",
wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
+ VNDR_IE_PRBREQ_FLAG, sme->ie, sme->ie_len);
+ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
}
@@ -2177,10 +2238,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
} else {
wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
}
/* find the WPSIE */
@@ -2249,7 +2310,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
if (ext_join_params == NULL) {
err = -ENOMEM;
- wl_clr_drv_status(wl, CONNECTING);
+ wl_clr_drv_status(wl, CONNECTING, dev);
goto exit;
}
ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
@@ -2258,12 +2319,13 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
/* Set up join scan parameters */
ext_join_params->scan.scan_type = -1;
ext_join_params->scan.nprobes = 2;
- /* increate dwell time to receive probe response
- * from target AP at a noisy air
+ /* increate dwell time to receive probe response or detect Beacon
+ * from target AP at a noisy air only during connect command
*/
- ext_join_params->scan.active_time = 150;
- ext_join_params->scan.passive_time = 300;
+ ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3;
+ ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3;
ext_join_params->scan.home_time = -1;
+
if (sme->bssid)
memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
else
@@ -2288,12 +2350,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
ext_join_params->ssid.SSID_len));
}
- wl_set_drv_status(wl, CONNECTING);
- err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
- sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
+ wl_set_drv_status(wl, CONNECTING, dev);
+ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync);
kfree(ext_join_params);
if (err) {
- wl_clr_drv_status(wl, CONNECTING);
+ wl_clr_drv_status(wl, CONNECTING, dev);
if (err == BCME_UNSUPPORTED) {
WL_DBG(("join iovar is not supported\n"));
goto set_ssid;
@@ -2309,7 +2371,7 @@ set_ssid:
join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
- wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
+ wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID);
if (sme->bssid)
memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
else
@@ -2322,11 +2384,11 @@ set_ssid:
WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
join_params.ssid.SSID_len));
}
- wl_set_drv_status(wl, CONNECTING);
+ wl_set_drv_status(wl, CONNECTING, dev);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
if (err) {
WL_ERR(("error (%d)\n", err));
- wl_clr_drv_status(wl, CONNECTING);
+ wl_clr_drv_status(wl, CONNECTING, dev);
}
exit:
return err;
@@ -2343,23 +2405,23 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
u8 *curbssid;
WL_ERR(("Reason %d\n", reason_code));
CHECK_SYS_UP(wl);
- act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
- if (likely(act)) {
+ act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT);
+ curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID);
+ if (act) {
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
- wl_set_drv_status(wl, DISCONNECTING);
+ wl_set_drv_status(wl, DISCONNECTING, dev);
scbval.val = reason_code;
memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
scbval.val = htod32(scbval.val);
err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t), true);
if (unlikely(err)) {
- wl_clr_drv_status(wl, DISCONNECTING);
+ wl_clr_drv_status(wl, DISCONNECTING, dev);
WL_ERR(("error (%d)\n", err));
return err;
}
@@ -2409,7 +2471,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
txpwrmw = 0xffff;
else
txpwrmw = (u16) dbm;
- err = wl_dev_intvar_set(ndev, "qtxpower",
+ err = wldev_iovar_setint(ndev, "qtxpower",
(s32) (bcm_mw_to_qdbm(txpwrmw)));
if (unlikely(err)) {
WL_ERR(("qtxpower error (%d)\n", err));
@@ -2429,7 +2491,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
s32 err = 0;
CHECK_SYS_UP(wl);
- err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
+ err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -2478,7 +2540,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
struct wl_wsec_key key;
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
- s32 mode = get_mode_by_netdev(wl, dev);
+ s32 mode = wl_get_mode_by_netdev(wl, dev);
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -2490,8 +2552,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
if (key.len == 0) {
/* key delete */
swap_key_from_BE(&key);
- wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("key delete error (%d)\n", err));
return err;
@@ -2549,11 +2611,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
swap_key_from_BE(&key);
-#ifdef CONFIG_WIRELESS_EXT
- dhd_wait_pend8021x(dev);
-#endif
- wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
@@ -2574,7 +2633,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 keybuf[8];
s32 bssidx = 0;
struct wl_priv *wl = wiphy_priv(wiphy);
- s32 mode = get_mode_by_netdev(wl, dev);
+ s32 mode = wl_get_mode_by_netdev(wl, dev);
WL_DBG(("key index (%d)\n", key_idx));
CHECK_SYS_UP(wl);
@@ -2635,8 +2694,8 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
/* Set the new key/index */
swap_key_from_BE(&key);
- err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
@@ -2672,15 +2731,15 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP(wl);
memset(&key, 0, sizeof(key));
- key.index = (u32) key_idx;
key.flags = WL_PRIMARY_KEY;
key.algo = CRYPTO_ALGO_OFF;
+ key.index = (u32) key_idx;
WL_DBG(("key index (%d)\n", key_idx));
/* Set the new key/index */
swap_key_from_BE(&key);
- wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
if (err == -EINVAL) {
if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
@@ -2724,7 +2783,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
}
switch (wsec & ~SES_OW_ENABLED) {
case WEP_ENABLED:
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
params.cipher = WLAN_CIPHER_SUITE_WEP40;
WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
@@ -2774,15 +2833,15 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
CHECK_SYS_UP(wl);
- if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
+ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
- ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
+ ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (err < 0) {
WL_ERR(("GET STA INFO failed, %d\n", err));
return err;
}
sinfo->filled = STATION_INFO_INACTIVE_TIME;
- sta = (sta_info_t *)ioctlbuf;
+ sta = (sta_info_t *)wl->ioctl_buf;
sta->len = dtoh16(sta->len);
sta->cap = dtoh16(sta->cap);
sta->flags = dtoh32(sta->flags);
@@ -2798,50 +2857,48 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
sta->idle * 1000));
#endif
- } else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
- u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID);
-
- if (!wl_get_drv_status(wl, CONNECTED) ||
- (dhd_is_associated(dhd, NULL) == FALSE)) {
- WL_ERR(("NOT assoc\n"));
- err = -ENODEV;
- goto get_station_err;
- }
- if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
- WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
- MAC2STR(mac), MAC2STR(curmacp)));
- }
-
- /* Report the current tx rate */
- err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
- if (err) {
- WL_ERR(("Could not get rate (%d)\n", err));
- } else {
- rate = dtoh32(rate);
- sinfo->filled |= STATION_INFO_TX_BITRATE;
- sinfo->txrate.legacy = rate * 5;
- WL_DBG(("Rate %d Mbps\n", (rate / 2)));
- }
+ } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
+ u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
+ err = -ENODEV;
+ if (!wl_get_drv_status(wl, CONNECTED, dev) ||
+ (dhd_is_associated(dhd, NULL, &err) == FALSE)) {
+ WL_ERR(("NOT assoc: %d\n", err));
+ goto get_station_err;
+ }
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+ WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
+ MAC2STR(mac), MAC2STR(curmacp)));
+ }
- memset(&scb_val, 0, sizeof(scb_val));
- scb_val.val = 0;
- err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
- sizeof(scb_val_t), false);
- if (err) {
- WL_ERR(("Could not get rssi (%d)\n", err));
- goto get_station_err;
- }
+ /* Report the current tx rate */
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+ rate = dtoh32(rate);
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+ }
- rssi = dtoh32(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = rssi;
- WL_DBG(("RSSI %d dBm\n", rssi));
+ memset(&scb_val, 0, sizeof(scb_val));
+ scb_val.val = 0;
+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+ sizeof(scb_val_t), false);
+ if (err) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ goto get_station_err;
+ }
+ rssi = dtoh32(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
get_station_err:
- if (err) {
+ if (err && (err != -ETIMEDOUT) && (err != -EIO)) {
/* Disconnect due to zero BSSID or error to get RSSI */
- WL_ERR(("force cfg80211_disconnected\n"));
- wl_clr_drv_status(wl, CONNECTED);
+ WL_ERR(("force cfg80211_disconnected: %d\n", err));
+ wl_clr_drv_status(wl, CONNECTED, dev);
cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
wl_link_down(wl);
}
@@ -2859,14 +2916,14 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
struct wl_priv *wl = wiphy_priv(wiphy);
CHECK_SYS_UP(wl);
- pm = enabled ? PM_FAST : PM_OFF;
- /* Do not enable the power save after assoc if it is p2p interface */
- if (wl->p2p && wl->p2p->vif_created) {
- WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n"));
- pm = PM_OFF;
+
+ WL_DBG(("Enter : power save %s\n", (enabled ? "enable" : "disable")));
+ if (wl->p2p_net == dev) {
+ return err;
}
+
+ pm = enabled ? PM_FAST : PM_OFF;
pm = htod32(pm);
- WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
if (unlikely(err)) {
if (err == -ENODEV)
@@ -2875,6 +2932,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("error (%d)\n", err));
return err;
}
+ WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
return err;
}
@@ -2908,11 +2966,11 @@ static __used u32 wl_find_msb(u16 bit16)
static s32 wl_cfg80211_resume(struct wiphy *wiphy)
{
struct wl_priv *wl = wiphy_priv(wiphy);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 err = 0;
- if (unlikely(!wl_get_drv_status(wl, READY))) {
- WL_INFO(("device is not ready : status (%d)\n",
- (int)wl->status));
+ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) {
+ WL_INFO(("device is not ready\n"));
return 0;
}
@@ -2929,33 +2987,38 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
{
#ifdef DHD_CLEAR_ON_SUSPEND
struct wl_priv *wl = wiphy_priv(wiphy);
+ struct net_info *iter, *next;
struct net_device *ndev = wl_to_prmry_ndev(wl);
unsigned long flags;
- if (unlikely(!wl_get_drv_status(wl, READY))) {
+ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) {
WL_INFO(("device is not ready : status (%d)\n",
(int)wl->status));
return 0;
}
-
- wl_set_drv_status(wl, SCAN_ABORTING);
+ for_each_ndev(wl, iter, next)
+ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
wl_term_iscan(wl);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
- wl_clr_drv_status(wl, SCANNING);
- wl_clr_drv_status(wl, SCAN_ABORTING);
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
- if (wl_get_drv_status(wl, CONNECTING)) {
- wl_bss_connect_done(wl, ndev, NULL, NULL, false);
+ for_each_ndev(wl, iter, next) {
+ wl_clr_drv_status(wl, SCANNING, iter->ndev);
+ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
}
-#endif
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+ for_each_ndev(wl, iter, next) {
+ if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) {
+ wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false);
+ }
+ }
+#endif /* DHD_CLEAR_ON_SUSPEND */
return 0;
}
-static __used s32
+static s32
wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
s32 err)
{
@@ -2963,10 +3026,13 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
struct wl_priv *wl = wlcfg_drv_priv;
struct net_device *primary_dev = wl_to_prmry_ndev(wl);
- /* Firmware is supporting pmk list only for STA interface i.e. primary interface
- * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
- * Do we really need to support PMK cache in P2P in firmware?
- */
+ if (!pmk_list) {
+ printk("pmk_list is NULL\n");
+ return -EINVAL;
+ }
+ /* pmk list is supported only for STA interface i.e. primary interface
+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+ */
if (primary_dev != dev) {
WL_INFO(("Not supporting Flushing pmklist on virtual"
" interfaces than primary interface\n"));
@@ -2982,8 +3048,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
}
}
if (likely(!err)) {
- err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
- sizeof(*pmk_list));
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
+ sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
}
return err;
@@ -3084,7 +3150,7 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
}
-wl_scan_params_t *
+static wl_scan_params_t *
wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
{
wl_scan_params_t *params;
@@ -3116,47 +3182,12 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
/* Our scan params have 1 channel and 0 ssids */
params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
- (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
*out_params_size = params_size; /* rtn size to the caller */
return params;
}
-s32
-wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
-{
- wl_scan_params_t *params = NULL;
- s32 params_size = 0;
- s32 err = BCME_OK;
- unsigned long flags;
-
- WL_DBG(("Enter\n"));
-
- /* Our scan params only need space for 1 channel and 0 ssids */
- params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
- if (params == NULL) {
- WL_ERR(("scan params allocation failed \n"));
- err = -ENOMEM;
- } else {
- /* Do a scan abort to stop the driver's scan engine */
- err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
- if (err < 0) {
- WL_ERR(("scan abort failed \n"));
- }
- }
- del_timer_sync(&wl->scan_timeout);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
- if (wl->scan_request) {
- cfg80211_scan_done(wl->scan_request, true);
- wl->scan_request = NULL;
- }
- wl_clr_drv_status(wl, SCANNING);
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
- if (params)
- kfree(params);
- return err;
-}
-
static s32
wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel * channel,
@@ -3164,36 +3195,48 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
unsigned int duration, u64 *cookie)
{
s32 target_channel;
+ u32 id;
+ struct ether_addr primary_mac;
+ struct net_device *ndev = NULL;
s32 err = BCME_OK;
struct wl_priv *wl = wiphy_priv(wiphy);
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
- if (likely(wl_get_drv_status(wl, SCANNING))) {
- wl_cfg80211_scan_abort(wl, dev);
+
+ if (wl->p2p_net == dev) {
+ ndev = wl_to_prmry_ndev(wl);
+ } else {
+ ndev = dev;
}
+ if (wl_get_drv_status(wl, SCANNING, ndev)) {
+ wl_notify_escan_complete(wl, ndev, true, true);
+ }
target_channel = ieee80211_frequency_to_channel(channel->center_freq);
memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
wl->remain_on_chan_type = channel_type;
- wl->cache_cookie = *cookie;
+ id = ++wl->last_roc_id;
+ if (id == 0)
+ id = ++wl->last_roc_id;
+ *cookie = id;
cfg80211_ready_on_channel(dev, *cookie, channel,
channel_type, duration, GFP_KERNEL);
- if (!p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+ if (wl->p2p && !wl->p2p->on) {
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
/* In case of p2p_listen command, supplicant send remain_on_channel
* without turning on P2P
*/
p2p_on(wl) = true;
- err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
+ err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0);
if (unlikely(err)) {
goto exit;
}
}
- if (p2p_on(wl))
+ if (p2p_is_on(wl))
wl_cfgp2p_discover_listen(wl, target_channel, duration);
@@ -3211,39 +3254,143 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev
}
static s32
-wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl)
+{
+ wl_af_params_t *tx_act_frm;
+ struct net_device *dev = wl->afx_hdl->dev;
+ if (!p2p_is_on(wl))
+ return -1;
+
+ if (dev == wl->p2p_net) {
+ dev = wl_to_prmry_ndev(wl);
+ }
+
+ tx_act_frm = wl->afx_hdl->pending_tx_act_frm;
+ WL_DBG(("Sending the action frame\n"));
+ wl->afx_hdl->pending_tx_act_frm = NULL;
+ if (tx_act_frm != NULL) {
+ /* Suspend P2P discovery's search-listen to prevent it from
+ * starting a scan or changing the channel.
+ */
+ wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev);
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ wl_notify_escan_complete(wl, dev, true, true);
+ wl_cfgp2p_discover_enable_search(wl, false);
+ tx_act_frm->channel = wl->afx_hdl->peer_chan;
+ wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev,
+ tx_act_frm, wl->afx_hdl->bssidx)) ? false : true;
+ }
+ return 0;
+}
+static void
+wl_cfg80211_afx_handler(struct work_struct *work)
+{
+
+ struct afx_hdl *afx_instance;
+ struct wl_priv *wl = wlcfg_drv_priv;
+ afx_instance = container_of(work, struct afx_hdl, work);
+ if (afx_instance != NULL) {
+ wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev,
+ wl->afx_hdl->bssidx, 0);
+ }
+}
+
+static bool
+wl_cfg80211_send_at_common_channel(struct wl_priv *wl,
+ struct net_device *dev,
+ wl_af_params_t *af_params)
+{
+ WL_DBG((" enter ) \n"));
+ /* initialize afx_hdl */
+ wl->afx_hdl->pending_tx_act_frm = af_params;
+ wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev);
+ wl->afx_hdl->dev = dev;
+ wl->afx_hdl->retry = 0;
+ wl->afx_hdl->peer_chan = WL_INVALID;
+ wl->afx_hdl->ack_recv = false;
+ memcpy(wl->afx_hdl->pending_tx_dst_addr.octet,
+ af_params->action_frame.da.octet,
+ sizeof(wl->afx_hdl->pending_tx_dst_addr.octet));
+ /* Loop to wait until we have sent the pending tx action frame or the
+ * pending action frame tx is cancelled.
+ */
+ while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) &&
+ (wl->afx_hdl->peer_chan == WL_INVALID)) {
+ wl_set_drv_status(wl, SENDING_ACT_FRM, dev);
+ wl_set_drv_status(wl, SCANNING, dev);
+ WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
+ wl->afx_hdl->retry));
+ /* Do find_peer_for_action */
+ schedule_work(&wl->afx_hdl->work);
+ wait_for_completion(&wl->act_frm_scan);
+ wl->afx_hdl->retry++;
+ }
+ if (wl->afx_hdl->peer_chan != WL_INVALID)
+ wl_cfg80211_send_pending_tx_act_frm(wl);
+ else {
+ WL_ERR(("Couldn't find the peer after %d retries\n",
+ wl->afx_hdl->retry));
+ }
+ wl->afx_hdl->dev = NULL;
+ wl->afx_hdl->bssidx = WL_INVALID;
+ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev);
+ if (wl->afx_hdl->ack_recv)
+ return true; /* ACK */
+ else
+ return false; /* NO ACK */
+}
+
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
struct ieee80211_channel *channel, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8* buf, size_t len, u64 *cookie)
+ const u8* buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ bool no_cck,
+#endif
+ u64 *cookie)
{
wl_action_frame_t *action_frame;
wl_af_params_t *af_params;
wifi_p2p_ie_t *p2p_ie;
wpa_ie_fixed_t *wps_ie;
+ wifi_wfd_ie_t *wfd_ie;
+ scb_val_t scb_val;
const struct ieee80211_mgmt *mgmt;
struct wl_priv *wl = wiphy_priv(wiphy);
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ struct net_device *dev = NULL;
s32 err = BCME_OK;
s32 bssidx = 0;
u32 p2pie_len = 0;
u32 wpsie_len = 0;
- u16 fc;
+ u32 wfdie_len = 0;
+ u32 id;
+ u32 retry = 0;
bool ack = false;
- wifi_p2p_pub_act_frame_t *act_frm;
+ wifi_p2p_pub_act_frame_t *act_frm = NULL;
+ wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+ int retry_cnt = 0;
+
WL_DBG(("Enter \n"));
+
+ if (ndev == wl->p2p_net) {
+ dev = wl_to_prmry_ndev(wl);
+ } else {
+ /* If TX req is for any valid ifidx. Use as is */
+ dev = ndev;
+ }
+
/* find bssidx based on ndev */
bssidx = wl_cfgp2p_find_idx(wl, dev);
- /* cookie generation */
- *cookie = (unsigned long) buf;
-
if (bssidx == -1) {
WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
return -ENODEV;
}
- if (wl->p2p_supported && p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+ if (p2p_is_on(wl)) {
/* Suspend P2P discovery search-listen to prevent it from changing the
* channel.
*/
@@ -3252,50 +3399,74 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
return -EFAULT;
}
}
-
- mgmt = (const struct ieee80211_mgmt *) buf;
- fc = mgmt->frame_control;
- if (fc != IEEE80211_STYPE_ACTION) {
- if (fc == IEEE80211_STYPE_PROBE_RESP) {
+ *cookie = 0;
+ id = wl->send_action_id++;
+ if (id == 0)
+ id = wl->send_action_id++;
+ *cookie = id;
+ mgmt = (const struct ieee80211_mgmt *)buf;
+ if (ieee80211_is_mgmt(mgmt->frame_control)) {
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
s32 ie_len = len - ie_offset;
if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
!= NULL) {
/* Total length of P2P Information Element */
p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
- /* Have to change p2p device address in dev_info attribute
- * because Supplicant use primary eth0 address
- */
- #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie,
- &wl->p2p_dev_addr, P2P_SEID_DEV_INFO);
- #endif
+ }
+ if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)(buf + ie_offset), ie_len))
+ != NULL) {
+ /* Total length of WFD Information Element */
+ wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id);
}
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len))
!= NULL) {
/* Order of Vendor IE is 1) WPS IE +
* 2) P2P IE created by supplicant
* So, it is ok to find start address of WPS IE
- * to save IEs to firmware
+ * to save IEs
*/
wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
sizeof(wps_ie->tag);
wl_cfgp2p_set_management_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
- (u8 *)wps_ie, wpsie_len + p2pie_len);
+ (u8 *)wps_ie, wpsie_len + p2pie_len + wfdie_len);
}
+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+ } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
+ ieee80211_is_deauth(mgmt->frame_control)) {
+ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
+ scb_val.val = mgmt->u.disassoc.reason_code;
+ wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true);
+ WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
+ scb_val.val));
+ /* Wait for the deauth event to come, supplicant will do the delete iface immediately
+ * and we will have problem in sending deauth frame if we delete the bss in firmware
+ */
+ wl_delay(400);
+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+
+ } else if (ieee80211_is_action(mgmt->frame_control)) {
+ /* Abort the dwell time of any previous off-channel
+ * action frame that may be still in effect. Sending
+ * off-channel action frames relies on the driver's
+ * scan engine. If a previous off-channel action frame
+ * tx is still in progress (including the dwell time),
+ * then this new action frame will not be sent out.
+ */
+ wl_notify_escan_complete(wl, dev, true, true);
+
}
- cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
- goto exit;
+
} else {
- /* Abort the dwell time of any previous off-channel action frame that may
- * be still in effect. Sending off-channel action frames relies on the
- * driver's scan engine. If a previous off-channel action frame tx is
- * still in progress (including the dwell time), then this new action
- * frame will not be sent out.
- */
- wl_cfg80211_scan_abort(wl, dev);
+ WL_ERR(("Driver only allows MGMT packet type\n"));
+ goto exit;
}
+
af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
if (af_params == NULL)
@@ -3307,7 +3478,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
action_frame = &af_params->action_frame;
/* Add the packet Id */
- action_frame->packetId = (u32) action_frame;
+ action_frame->packetId = *cookie;
WL_DBG(("action frame %d\n", action_frame->packetId));
/* Add BSSID */
memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
@@ -3321,6 +3492,15 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
af_params->channel =
ieee80211_frequency_to_channel(channel->center_freq);
+ if (channel->band == IEEE80211_BAND_5GHZ) {
+ WL_DBG(("5GHz channel %d", af_params->channel));
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &af_params->channel, sizeof(af_params->channel), true);
+ if (err < 0) {
+ WL_ERR(("WLC_SET_CHANNEL error %d\n", err));
+ }
+ }
+
/* Add the dwell time
* Dwell time to stay off-channel to wait for a response action frame
* after transmitting an GO Negotiation action frame
@@ -3328,28 +3508,74 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
af_params->dwell_time = WL_DWELL_TIME;
memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
+ if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) {
+ act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
+ WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n",
+ action_frame->len, af_params->channel,
+ act_frm->category, act_frm->subtype));
+ } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) {
+ p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data);
+ WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n",
+ action_frame->len, af_params->channel,
+ p2p_act_frm->category, p2p_act_frm->subtype));
+ } else if (wl_cfgp2p_is_gas_action(action_frame->data, action_frame->len)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (action_frame->data);
+ WL_DBG(("Service Discovery action_frame->len: %d chan %d category %d action %d\n",
+ action_frame->len, af_params->channel,
+ sd_act_frm->category, sd_act_frm->action));
+
+ }
+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len);
+ /*
+ * To make sure to send successfully action frame, we have to turn off mpc
+ */
- act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
- WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
- action_frame->len, af_params->channel,
- act_frm->category, act_frm->subtype));
- if (wl->p2p->vif_created) {
- /*
- * To make sure to send successfully action frame, we have to turn off mpc
+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
+ (act_frm->subtype == P2P_PAF_GON_RSP) ||
+ (act_frm->subtype == P2P_PAF_GON_CONF) ||
+ (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
+ wldev_iovar_setint(dev, "mpc", 0);
+ }
+ if (act_frm->subtype == P2P_PAF_GON_RSP)
+ retry_cnt = 1;
+ else retry_cnt = WL_ACT_FRAME_RETRY;
+
+ if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
+ af_params->dwell_time = WL_LONG_DWELL_TIME;
+ } else if (act_frm &&
+ (act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
+ act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
+ act_frm->subtype == P2P_PAF_GON_RSP)) {
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ }
+
+ if (IS_P2P_SOCIAL(af_params->channel) &&
+ (IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], action_frame->len) ||
+ IS_GAS_REQ(sd_act_frm, action_frame->len)) &&
+ wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
+ /* channel offload require P2P IE for Probe request
+ * otherwise, we will use wl_cfgp2p_tx_action_frame directly.
+ * channel offload for action request frame
*/
- if ((act_frm->subtype == P2P_PAF_GON_REQ)||
- (act_frm->subtype == P2P_PAF_GON_RSP)) {
- wldev_iovar_setint(dev, "mpc", 0);
- } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
- wldev_iovar_setint(dev, "mpc", 1);
- } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
- af_params->dwell_time = WL_LONG_DWELL_TIME;
- }
- }
- ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
- cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL);
+ /* channel offload for action request frame */
+ ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params);
+ } else {
+ ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
+ if (!ack) {
+ for (retry = 1; retry < retry_cnt; retry++) {
+ ack = (wl_cfgp2p_tx_action_frame(wl, dev,
+ af_params, bssidx)) ? false : true;
+ if (ack)
+ break;
+ }
+ }
+ }
+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL);
+ if (act_frm && act_frm->subtype == P2P_PAF_GON_CONF) {
+ wldev_iovar_setint(dev, "mpc", 1);
+ }
kfree(af_params);
exit:
return err;
@@ -3403,8 +3629,21 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
{
s32 channel;
s32 err = BCME_OK;
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ if (wl->p2p_net == dev) {
+ dev = wl_to_prmry_ndev(wl);
+ }
channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+ if (wl_get_drv_status(wl, AP_CREATING, dev)) {
+ WL_TRACE(("<0> %s: as!!! in AP creating mode, save chan num:%d\n",
+ __FUNCTION__, channel));
+ wl->hostapd_chan = channel;
+ if (channel == 14)
+ return err; /* hostapd requested ch auto-select, will be done later */
+ }
+
WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
dev->ifindex, channel_type, channel));
err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true);
@@ -3419,8 +3658,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
{
s32 len = 0;
s32 err = BCME_OK;
- u16 auth = 0; /* d11 open authentication */
- u16 count;
+ u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
u32 wsec;
u32 pval = 0;
u32 gval = 0;
@@ -3458,7 +3696,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
len -= WPA_SUITE_LEN;
/* check the unicast cipher */
ucast = (wpa_suite_ucast_t *)&mcast[1];
- count = ltoh16_ua(&ucast->count);
+ ltoh16_ua(&ucast->count);
tmp = ucast->list[0].oui;
switch (tmp[DOT11_OUI_LEN]) {
case WPA_CIPHER_NONE:
@@ -3481,7 +3719,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
wsec = (pval | gval | SES_OW_ENABLED);
/* check the AKM */
mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1];
- count = ltoh16_ua(&mgmt->count);
+ ltoh16_ua(&mgmt->count);
tmp = (u8 *)&mgmt->list[0];
switch (tmp[DOT11_OUI_LEN]) {
case RSN_AKM_NONE:
@@ -3524,7 +3762,7 @@ wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
wpa_suite_mcast_t *mcast;
wpa_suite_ucast_t *ucast;
wpa_suite_auth_key_mgmt_t *mgmt;
- u16 auth = 0; /* d11 open authentication */
+ u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
u16 count;
s32 err = BCME_OK;
s32 len = 0;
@@ -3677,20 +3915,28 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
wpa_ie_fixed_t *wpa_ie;
bcm_tlv_t *wpa2_ie;
wifi_p2p_ie_t *p2p_ie;
+ wifi_wfd_ie_t *wfd_ie;
bool is_bssup = false;
bool update_bss = false;
bool pbc = false;
u16 wpsie_len = 0;
u16 p2pie_len = 0;
+ u32 wfdie_len = 0;
u8 beacon_ie[IE_MAX_LEN];
s32 ie_offset = 0;
- s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
+ s32 bssidx = 0;
s32 infra = 1;
s32 join_params_size = 0;
s32 ap = 0;
WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
info->interval, info->dtim_period, info->head_len, info->tail_len));
- if (wl->p2p_supported && p2p_on(wl) &&
+
+ if (wl->p2p_net == dev) {
+ dev = wl_to_prmry_ndev(wl);
+ }
+
+ bssidx = wl_cfgp2p_find_idx(wl, dev);
+ if (p2p_is_on(wl) &&
(bssidx == wl_to_p2p_bss_bssidx(wl,
P2PAPI_BSSCFG_CONNECTION))) {
memset(beacon_ie, 0, sizeof(beacon_ie));
@@ -3728,21 +3974,29 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) {
/* Total length of P2P Information Element */
p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
- #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
- /* Have to change device address in dev_id attribute because Supplicant
- * use primary eth0 address
- */
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID);
- #endif
memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len);
} else {
WL_ERR(("No P2PIE in beacon \n"));
}
+ /* find the WFD IEs */
+ if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)info->tail, info->tail_len)) != NULL) {
+ /* Total length of P2P Information Element */
+ wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id);
+ if ((wpsie_len + p2pie_len + wfdie_len) < IE_MAX_LEN) {
+ memcpy(&beacon_ie[wpsie_len + p2pie_len], wfd_ie, wfdie_len);
+ } else {
+ WL_ERR(("Found WFD IE but there is no space, (%d)(%d)(%d)\n",
+ wpsie_len, p2pie_len, wfdie_len));
+ wfdie_len = 0;
+ }
+ } else {
+ WL_ERR(("No WFDIE in beacon \n"));
+ }
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
- beacon_ie, wpsie_len + p2pie_len);
+ beacon_ie, wpsie_len + p2pie_len + wfdie_len);
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3763,17 +4017,18 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
goto exit;
}
err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
- sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
+ sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &wl->ioctl_buf_sync);
if (err < 0) {
WL_ERR(("GO SSID setting error %d\n", err));
goto exit;
}
- if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
+ if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) {
WL_ERR(("GO Bring up error %d\n", err));
goto exit;
}
}
- } else if (wl_get_drv_status(wl, AP_CREATING)) {
+ } else if (wl_get_drv_status(wl, AP_CREATING, dev)) {
ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
ap = 1;
/* find the SSID */
@@ -3791,6 +4046,26 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("setting AP mode failed %d \n", err));
return err;
}
+
+ /* if requested, do softap ch autoselect */
+ if (wl->hostapd_chan == 14) {
+ int auto_chan;
+ if ((err = wldev_get_auto_channel(dev, &auto_chan)) != 0) {
+ WL_ERR(("softap: auto chan select failed,"
+ " will use ch 6\n"));
+ auto_chan = 6;
+ } else {
+ printf("<0>softap: got auto ch:%d\n", auto_chan);
+ }
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &auto_chan, sizeof(auto_chan), true);
+ if (err < 0) {
+ WL_ERR(("softap: WLC_SET_CHANNEL error %d chip"
+ " may not be supporting this channel\n", err));
+ return err;
+ }
+ }
+
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
DOT11_MNG_RSN_ID)) != NULL) {
@@ -3846,9 +4121,9 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
memcpy(beacon_ie, wps_ie, wpsie_len);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len);
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else {
WL_DBG(("No WPSIE in beacon \n"));
}
@@ -3879,11 +4154,11 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
/* create softap */
if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
join_params_size, true)) == 0) {
- wl_clr_drv_status(wl, AP_CREATING);
- wl_set_drv_status(wl, AP_CREATED);
+ wl_clr_drv_status(wl, AP_CREATING, dev);
+ wl_set_drv_status(wl, AP_CREATED, dev);
}
}
- } else if (wl_get_drv_status(wl, AP_CREATED)) {
+ } else if (wl_get_drv_status(wl, AP_CREATED, dev)) {
ap = 1;
/* find the WPSIE */
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
@@ -3899,14 +4174,14 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
WL_DBG((" WPS IE is changed\n"));
kfree(wl->ap_info->wps_ie);
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else if (wl->ap_info->wps_ie == NULL) {
WL_DBG((" WPS IE is added\n"));
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
}
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3972,12 +4247,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
}
if (update_bss) {
wl->ap_info->security_mode = true;
- wl_cfgp2p_bss(dev, bssidx, 0);
+ wl_cfgp2p_bss(wl, dev, bssidx, 0);
if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
return BCME_ERROR;
}
- wl_cfgp2p_bss(dev, bssidx, 1);
+ wl_cfgp2p_bss(wl, dev, bssidx, 1);
}
}
} else {
@@ -3990,6 +4265,108 @@ exit:
return err;
}
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME 30
+#define PNO_REPEAT 4
+#define PNO_FREQ_EXPO_MAX 3
+int wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *request)
+{
+ ushort pno_time = PNO_TIME;
+ int pno_repeat = PNO_REPEAT;
+ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
+ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssid = NULL;
+ int ssid_count = 0;
+ int i;
+ int ret = 0;
+
+ WL_DBG(("Enter n_match_sets:%d n_ssids:%d \n",
+ request->n_match_sets, request->n_ssids));
+ WL_DBG(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+#if defined(WL_ENABLE_P2P_IF)
+ /* While GO is operational, PNO is not supported */
+ if (dhd_cfg80211_get_opmode(wl) & P2P_GO_ENABLED) {
+ WL_DBG(("PNO not enabled! op_mode: P2P GO"));
+ return -1;
+ }
+#endif
+
+ if (!request || !request->n_ssids || !request->n_match_sets) {
+ WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
+ return -EINVAL;
+ }
+
+ memset(&ssids_local, 0, sizeof(ssids_local));
+
+ if (request->n_match_sets > 0) {
+ for (i = 0; i < request->n_match_sets; i++) {
+ ssid = &request->match_sets[i].ssid;
+ memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len);
+ ssids_local[i].SSID_len = ssid->ssid_len;
+ WL_DBG((">>> PNO filter set for ssid (%s) \n", ssid->ssid));
+ ssid_count++;
+ }
+ }
+
+ if (request->n_ssids > 0) {
+ for (i = 0; i < request->n_ssids; i++) {
+ /* Active scan req for ssids */
+ WL_DBG((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid));
+
+ /* match_set ssids is a supert set of n_ssid list, so we need
+ * not add these set seperately
+ */
+ }
+ }
+
+ if (ssid_count) {
+ if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets,
+ pno_time, pno_repeat, pno_freq_expo_max)) < 0) {
+ WL_ERR(("PNO setup failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+
+ /* Enable the PNO */
+ if (dhd_dev_pno_enable(dev, 1) < 0) {
+ WL_ERR(("PNO enable failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+ wl->sched_scan_req = request;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct wl_priv *wl = wiphy_priv(wiphy);
+
+ WL_DBG(("Enter \n"));
+
+ if (dhd_dev_pno_enable(dev, 0) < 0)
+ WL_ERR(("PNO disable failed"));
+
+ if (dhd_dev_pno_reset(dev) < 0)
+ WL_ERR(("PNO reset failed"));
+
+ if (wl->scan_request && wl->sched_scan_running) {
+ wl_notify_escan_complete(wl, dev, true, true);
+ }
+
+ wl->sched_scan_req = NULL;
+ wl->sched_scan_running = FALSE;
+
+ return 0;
+}
+#endif /* WL_SCHED_SCAN */
+
static struct cfg80211_ops wl_cfg80211_ops = {
.add_virtual_intf = wl_cfg80211_add_virtual_iface,
.del_virtual_intf = wl_cfg80211_del_virtual_iface,
@@ -4022,9 +4399,13 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.set_channel = wl_cfg80211_set_channel,
.set_beacon = wl_cfg80211_add_set_beacon,
.add_beacon = wl_cfg80211_add_set_beacon,
+#ifdef WL_SCHED_SCAN
+ .sched_scan_start = wl_cfg80211_sched_scan_start,
+ .sched_scan_stop = wl_cfg80211_sched_scan_stop,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */
};
-static s32 wl_mode_to_nl80211_iftype(s32 mode)
+s32 wl_mode_to_nl80211_iftype(s32 mode)
{
s32 err = 0;
@@ -4042,30 +4423,30 @@ static s32 wl_mode_to_nl80211_iftype(s32 mode)
return err;
}
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev)
{
- struct wireless_dev *wdev;
s32 err = 0;
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (unlikely(!wdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
- return ERR_PTR(-ENOMEM);
- }
wdev->wiphy =
wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
if (unlikely(!wdev->wiphy)) {
WL_ERR(("Couldn not allocate wiphy device\n"));
err = -ENOMEM;
- goto wiphy_new_out;
+ return err;
}
set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
/* Report how many SSIDs Driver can support per Scan request */
wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#ifdef WL_SCHED_SCAN
+ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* WL_SCHED_SCAN */
wdev->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
- | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
+ BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
@@ -4085,6 +4466,9 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
#endif
WIPHY_FLAG_4ADDR_STATION;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+#endif
#ifdef ENABLE_CUSTOM_REGULATORY_DOMAIN
WL_DBG(("Registering custom regulatory)\n"));
@@ -4095,39 +4479,28 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
err = wiphy_register(wdev->wiphy);
if (unlikely(err < 0)) {
WL_ERR(("Couldn not register wiphy device (%d)\n", err));
- goto wiphy_register_out;
+ wiphy_free(wdev->wiphy);
}
- return wdev;
-
-wiphy_register_out:
- wiphy_free(wdev->wiphy);
-
-wiphy_new_out:
- kfree(wdev);
-
- return ERR_PTR(err);
+ return err;
}
static void wl_free_wdev(struct wl_priv *wl)
{
- int i;
struct wireless_dev *wdev = wl->wdev;
-
- if (unlikely(!wdev)) {
+ struct wiphy *wiphy;
+ if (!wdev) {
WL_ERR(("wdev is invalid\n"));
return;
}
-
- for (i = 0; i < VWDEV_CNT; i++) {
- if ((wl->vwdev[i] != NULL)) {
- kfree(wl->vwdev[i]);
- wl->vwdev[i] = NULL;
- }
- }
+ wiphy = wdev->wiphy;
wiphy_unregister(wdev->wiphy);
wdev->wiphy->dev.parent = NULL;
- wiphy_free(wdev->wiphy);
- kfree(wdev);
+
+ wl_delete_all_netinfo(wl);
+ wiphy_free(wiphy);
+ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl",
+ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
+ */
}
static s32 wl_inform_bss(struct wl_priv *wl)
@@ -4157,6 +4530,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
struct wl_cfg80211_bss_info *notif_bss_info;
struct wl_scan_req *sr = wl_to_sr(wl);
struct beacon_proberesp *beacon_proberesp;
+ struct cfg80211_bss *cbss = NULL;
s32 mgmt_type;
s32 signal;
u32 freq;
@@ -4180,6 +4554,11 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
notif_bss_info->rssi = dtoh16(bi->RSSI);
memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
mgmt_type = wl->active_scan ?
@@ -4206,8 +4585,13 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
#endif
channel = ieee80211_get_channel(wiphy, freq);
+ if (!channel) {
+ WL_ERR(("No valid channel"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
- WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM "
"mgmt_type %d frame_len %d\n", bi->SSID,
notif_bss_info->rssi, notif_bss_info->channel,
mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
@@ -4215,13 +4599,41 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
signal = notif_bss_info->rssi * 100;
- if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
- le16_to_cpu(notif_bss_info->frame_len),
- signal, GFP_KERNEL))) {
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ if (wl->p2p && wl->p2p_net && wl->scan_request &&
+ ((wl->scan_request->dev == wl->p2p_net) ||
+ (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))){
+#else
+ if (p2p_is_on(wl) && ( p2p_scan(wl) ||
+ (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))) {
+#endif
+ /* find the P2PIE, if we do not find it, we will discard this frame */
+ wifi_p2p_ie_t * p2p_ie;
+ if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable,
+ wl_get_ielen(wl))) == NULL) {
+ WL_ERR(("Couldn't find P2PIE in probe response/beacon\n"));
+ kfree(notif_bss_info);
+ return err;
+ }
+ }
+
+ if (!mgmt->u.probe_resp.timestamp) {
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec * 1000000)
+ + tv.tv_usec;
+ }
+
+ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+ le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL);
+ if (unlikely(!cbss)) {
WL_ERR(("cfg80211_inform_bss_frame error\n"));
kfree(notif_bss_info);
return -EINVAL;
}
+
+ cfg80211_put_bss(cbss);
kfree(notif_bss_info);
return err;
@@ -4233,7 +4645,7 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
u32 status = ntoh32(e->status);
u16 flags = ntoh16(e->flags);
- WL_DBG(("event %d, status %d\n", event, status));
+ WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
if (event == WLC_E_SET_SSID) {
if (status == WLC_E_STATUS_SUCCESS) {
if (!wl_is_ibssmode(wl, ndev))
@@ -4279,162 +4691,225 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
return false;
}
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
+ * to AP/P2P GO via events. If this change is backported to kernel for which
+ * this driver is being built, then define WL_CFG80211_STA_EVENT. You
+ * should use this new/del sta event mechanism for BRCM supplicant >= 22.
+ */
static s32
-wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
- bool act;
- bool isfree = false;
s32 err = 0;
- s32 freq;
- s32 channel;
- u8 body[200];
u32 event = ntoh32(e->event_type);
u32 reason = ntoh32(e->reason);
u32 len = ntoh32(e->datalen);
- u16 fc = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
+ bool isfree = false;
u8 *mgmt_frame;
u8 bsscfgidx = e->bsscfgidx;
+ s32 freq;
+ s32 channel;
+ u8 body[WL_FRAME_LEN];
+ u16 fc = 0;
struct ieee80211_supported_band *band;
struct ether_addr da;
struct ether_addr bssid;
struct wiphy *wiphy = wl_to_wiphy(wl);
channel_info_t ci;
+#else
+ struct station_info sinfo;
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
memset(body, 0, sizeof(body));
memset(&bssid, 0, ETHER_ADDR_LEN);
- WL_DBG(("Enter \n"));
+ WL_DBG(("Enter event %d ndev %p\n", event, ndev));
+ if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID)
+ return WL_INVALID;
- if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
- memcpy(body, data, len);
- wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
- NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
- memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
- err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
- switch (event) {
- case WLC_E_ASSOC_IND:
- fc = FC_ASSOC_REQ;
- break;
- case WLC_E_REASSOC_IND:
- fc = FC_REASSOC_REQ;
- break;
- case WLC_E_DISASSOC_IND:
- fc = FC_DISASSOC;
- break;
- case WLC_E_DEAUTH_IND:
- fc = FC_DISASSOC;
- break;
- case WLC_E_DEAUTH:
- fc = FC_DISASSOC;
- break;
- default:
- fc = 0;
- goto exit;
- }
- if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
- return err;
-
- channel = dtoh32(ci.hw_channel);
- if (channel <= CH_MAX_2G_CHANNEL)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (len > WL_FRAME_LEN) {
+ WL_ERR(("Received frame length %d from dongle is greater than"
+ " allocated body buffer len %d", len, WL_FRAME_LEN));
+ goto exit;
+ }
+ memcpy(body, data, len);
+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+ NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
+ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ switch (event) {
+ case WLC_E_ASSOC_IND:
+ fc = FC_ASSOC_REQ;
+ break;
+ case WLC_E_REASSOC_IND:
+ fc = FC_REASSOC_REQ;
+ break;
+ case WLC_E_DISASSOC_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH:
+ fc = FC_DISASSOC;
+ break;
+ default:
+ fc = 0;
+ goto exit;
+ }
+ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
+ return err;
+ channel = dtoh32(ci.hw_channel);
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ return -EINVAL;
+ }
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
- freq = ieee80211_channel_to_frequency(channel);
+ freq = ieee80211_channel_to_frequency(channel);
#else
- freq = ieee80211_channel_to_frequency(channel, band->band);
+ freq = ieee80211_channel_to_frequency(channel, band->band);
#endif
- err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
+ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
&mgmt_frame, &len, body);
- if (err < 0)
- goto exit;
- isfree = true;
+ if (err < 0)
+ goto exit;
+ isfree = true;
- if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
- } else if (event == WLC_E_DISASSOC_IND) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
- } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ } else if (event == WLC_E_DISASSOC_IND) {
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ }
+
+exit:
+ if (isfree)
+ kfree(mgmt_frame);
+ return err;
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */
+ sinfo.filled = 0;
+ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
+ reason == DOT11_SC_SUCCESS) {
+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ if (!data) {
+ WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
+ return -EINVAL;
}
+ sinfo.assoc_req_ies = data;
+ sinfo.assoc_req_ies_len = len;
+ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
+ } else if (event == WLC_E_DISASSOC_IND) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ }
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */
+ return err;
+}
+static s32
+wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ bool act;
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ u32 reason;
+
+ if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
+ wl_notify_connect_status_ap(wl, ndev, e, data);
} else {
- WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
- ntoh32(e->event_type), ntoh32(e->status)));
+ WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
+ ntoh32(e->event_type), ntoh32(e->status), ndev));
+ if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) {
+ reason = ntoh32(e->reason);
+ wl->deauth_reason = reason;
+ WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
+ }
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+ wl->deauth_reason = 0;
if (wl_is_ibssmode(wl, ndev)) {
printk("cfg80211_ibss_joined\n");
cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
GFP_KERNEL);
WL_DBG(("joined in IBSS network\n"));
} else {
- if (!wl_get_drv_status(wl, DISCONNECTING)) {
- printk("wl_bss_connect_done succeeded status=(0x%x)\n",
- (int)wl->status);
+ if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+ printk("wl_bss_connect_done succeeded\n");
wl_bss_connect_done(wl, ndev, e, data, true);
WL_DBG(("joined in BSS network \"%s\"\n",
((struct wlc_ssid *)
- wl_read_prof(wl, WL_PROF_SSID))->SSID));
+ wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID));
}
}
} else if (wl_is_linkdown(wl, e)) {
if (wl->scan_request) {
- del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
- wl_notify_escan_complete(wl, true);
- } else
+ wl_notify_escan_complete(wl, ndev, true, true);
+ } else {
+ del_timer_sync(&wl->scan_timeout);
wl_iscan_aborted(wl);
+ }
}
- if (wl_get_drv_status(wl, CONNECTED)) {
+ if (wl_get_drv_status(wl, CONNECTED, ndev)) {
scb_val_t scbval;
- u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
- printk("link down, call cfg80211_disconnected\n");
- wl_clr_drv_status(wl, CONNECTED);
- /* To make sure disconnect, explictly send dissassoc
- * for BSSID 00:00:00:00:00:00 issue
- */
- scbval.val = WLAN_REASON_DEAUTH_LEAVING;
-
- memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
- scbval.val = htod32(scbval.val);
- wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
- sizeof(scb_val_t), true);
- cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
- wl_link_down(wl);
- wl_init_prof(wl);
- } else if (wl_get_drv_status(wl, CONNECTING)) {
+ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
+ wl_clr_drv_status(wl, CONNECTED, ndev);
+ if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+ /* To make sure disconnect, explictly send dissassoc
+ * for BSSID 00:00:00:00:00:00 issue
+ */
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason));
+ cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL);
+ wl_link_down(wl);
+ wl_init_prof(wl, ndev);
+ }
+ }
+ else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
printk("link down, during connecting\n");
wl_bss_connect_done(wl, ndev, e, data, false);
}
- wl_clr_drv_status(wl, DISCONNECTING);
+ wl_clr_drv_status(wl, DISCONNECTING, ndev);
} else if (wl_is_nonetwork(wl, e)) {
printk("connect failed event=%d e->status 0x%x\n",
event, (int)ntoh32(e->status));
/* Clean up any pending scan request */
if (wl->scan_request) {
- del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
- wl_notify_escan_complete(wl, true);
- } else
+ wl_notify_escan_complete(wl, ndev, true, true);
+ } else {
+ del_timer_sync(&wl->scan_timeout);
wl_iscan_aborted(wl);
+ }
}
- if (wl_get_drv_status(wl, CONNECTING))
+ if (wl_get_drv_status(wl, CONNECTING, ndev))
wl_bss_connect_done(wl, ndev, e, data, false);
} else {
printk("%s nothing\n", __FUNCTION__);
}
}
-exit:
- if (isfree)
- kfree(mgmt_frame);
return err;
}
@@ -4448,50 +4923,17 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
u32 status = be32_to_cpu(e->status);
WL_DBG(("Enter \n"));
if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
- if (wl_get_drv_status(wl, CONNECTED))
+ if (wl_get_drv_status(wl, CONNECTED, ndev))
wl_bss_roaming_done(wl, ndev, e, data);
else
wl_bss_connect_done(wl, ndev, e, data, true);
act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
}
return err;
}
-static __used s32
-wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
-{
- struct wl_priv *wl = wlcfg_drv_priv;
- u32 buflen;
-
- buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
- BUG_ON(unlikely(!buflen));
-
- return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
-}
-
-static s32
-wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
- s32 buf_len)
-{
- struct wl_priv *wl = wlcfg_drv_priv;
- u32 len;
- s32 err = 0;
-
- len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
- BUG_ON(unlikely(!len));
- err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
- WL_IOCTL_LEN_MAX, false);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- return err;
- }
- memcpy(buf, wl->ioctl_buf, buf_len);
-
- return err;
-}
-
static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
{
wl_assoc_info_t assoc_info;
@@ -4499,8 +4941,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
s32 err = 0;
WL_DBG(("Enter \n"));
- err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
- WL_ASSOC_INFO_MAX);
+ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("could not get assoc info (%d)\n", err));
return err;
@@ -4518,8 +4960,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
}
if (assoc_info.req_len) {
- err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
- WL_ASSOC_INFO_MAX);
+ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("could not get assoc req (%d)\n", err));
return err;
@@ -4539,8 +4981,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
conn_info->req_ie_len = 0;
}
if (assoc_info.resp_len) {
- err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
- WL_ASSOC_INFO_MAX);
+ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("could not get assoc resp (%d)\n", err));
return err;
@@ -4602,26 +5044,27 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
struct wl_bss_info *bi;
struct wlc_ssid *ssid;
struct bcm_tlv *tim;
- u16 beacon_interval;
- u8 dtim_period;
+ s32 beacon_interval;
+ s32 dtim_period;
size_t ie_len;
u8 *ie;
u8 *curbssid;
s32 err = 0;
struct wiphy *wiphy;
+
wiphy = wl_to_wiphy(wl);
if (wl_is_ibssmode(wl, ndev))
return err;
- ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID);
+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
bss = cfg80211_get_bss(wiphy, NULL, curbssid,
ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
WLAN_CAPABILITY_ESS);
mutex_lock(&wl->usr_sync);
- if (unlikely(!bss)) {
+ if (!bss) {
WL_DBG(("Could not find the AP\n"));
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
@@ -4657,7 +5100,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
/*
* active scan was done so we could not get dtim
* information out of probe response.
- * so we speficially query dtim information to dongle.
+ * so we speficially query dtim information.
*/
err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
&dtim_period, sizeof(dtim_period), false);
@@ -4667,8 +5110,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
}
}
- wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
- wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+ wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
+ wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
update_bss_info_out:
mutex_unlock(&wl->usr_sync);
@@ -4684,8 +5127,8 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
u8 *curbssid;
wl_get_assoc_ies(wl, ndev);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
wl_update_bss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
cfg80211_roamed(ndev,
@@ -4697,7 +5140,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
WL_DBG(("Report roaming result\n"));
- wl_set_drv_status(wl, CONNECTED);
+ wl_set_drv_status(wl, CONNECTED, ndev);
return err;
}
@@ -4708,20 +5151,21 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
{
struct wl_connect_info *conn_info = wl_to_conn(wl);
s32 err = 0;
- u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
+
WL_DBG((" enter\n"));
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, ndev);
+ wl_notify_escan_complete(wl, ndev, true, true);
}
- if (wl_get_drv_status(wl, CONNECTING)) {
- wl_clr_drv_status(wl, CONNECTING);
+ if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+ wl_clr_drv_status(wl, CONNECTING, ndev);
if (completed) {
wl_get_assoc_ies(wl, ndev);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
wl_update_bss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
- wl_set_drv_status(wl, CONNECTED);
+ wl_set_drv_status(wl, CONNECTED, ndev);
}
cfg80211_connect_result(ndev,
curbssid,
@@ -4759,6 +5203,28 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
return 0;
}
+#ifdef PNO_SUPPORT
+static s32
+wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ WL_ERR((" PNO Event\n"));
+
+ mutex_lock(&wl->usr_sync);
+#ifndef WL_SCHED_SCAN
+ /* TODO: Use cfg80211_sched_scan_results(wiphy); */
+ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+#else
+ /* If cfg80211 scheduled scan is supported, report the pno results via sched
+ * scan results
+ */
+ wl_notify_sched_scan_results(wl, ndev, e, data);
+#endif /* WL_SCHED_SCAN */
+ mutex_unlock(&wl->usr_sync);
+ return 0;
+}
+#endif /* PNO_SUPPORT */
+
static s32
wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
@@ -4770,11 +5236,15 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
unsigned long flags;
WL_DBG(("Enter \n"));
+ if (!wl_get_drv_status(wl, SCANNING, ndev)) {
+ WL_ERR(("scan is not ready \n"));
+ return err;
+ }
if (wl->iscan_on && wl->iscan_kickstart)
return wl_wakeup_iscan(wl_to_iscan(wl));
mutex_lock(&wl->usr_sync);
- wl_clr_drv_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, ndev);
err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
sizeof(channel_inform), false);
if (unlikely(err)) {
@@ -4805,13 +5275,13 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
scan_done_out:
del_timer_sync(&wl->scan_timeout);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
WL_DBG(("cfg80211_scan_done\n"));
cfg80211_scan_done(wl->scan_request, false);
wl->scan_request = NULL;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
mutex_unlock(&wl->usr_sync);
return err;
}
@@ -4867,7 +5337,10 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
bool isfree = false;
s32 err = 0;
s32 freq;
- wifi_p2p_pub_act_frame_t *act_frm;
+ struct net_device *dev = NULL;
+ wifi_p2p_pub_act_frame_t *act_frm = NULL;
+ wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
wl_event_rx_frame_data_t *rxframe =
(wl_event_rx_frame_data_t*)data;
u32 event = ntoh32(e->event_type);
@@ -4877,22 +5350,32 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
memset(&bssid, 0, ETHER_ADDR_LEN);
+
+ if (wl->p2p_net == ndev) {
+ dev = wl_to_prmry_ndev(wl);
+ } else {
+ dev = ndev;
+ }
+
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
+ if (!band) {
+ WL_ERR(("No valid band"));
+ return -EINVAL;
+ }
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
freq = ieee80211_channel_to_frequency(channel);
#else
freq = ieee80211_channel_to_frequency(channel, band->band);
#endif
if (event == WLC_E_ACTION_FRAME_RX) {
- wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
- NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+ wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr",
+ NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
- wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
- memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
+ wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
&mgmt_frame, &mgmt_frame_len,
(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
@@ -4902,13 +5385,29 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
goto exit;
}
isfree = true;
- act_frm =
- (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ act_frm = (wifi_p2p_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ p2p_act_frm = (wifi_p2p_action_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ (void) p2p_act_frm;
+ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ (void) sd_act_frm;
+ }
+ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN);
/*
* After complete GO Negotiation, roll back to mpc mode
*/
- if (act_frm->subtype == P2P_PAF_GON_CONF) {
- wldev_iovar_setint(ndev, "mpc", 1);
+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
+ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+ wldev_iovar_setint(dev, "mpc", 1);
}
} else {
mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
@@ -4925,14 +5424,122 @@ exit:
return 0;
}
+#ifdef WL_SCHED_SCAN
+/* If target scan is not reliable, set the below define to "1" to do a
+ * full escan
+ */
+#define FULL_ESCAN_ON_PFN_NET_FOUND 0
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ wl_pfn_net_info_t *netinfo, *pnetinfo;
+ struct cfg80211_scan_request request;
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ int err = 0;
+ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
+ struct ieee80211_channel *channel = NULL;
+ int channel_req = 0;
+ int band = 0;
+ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
+
+ WL_DBG(("Enter\n"));
+
+ if (e->event_type == WLC_E_PFN_NET_LOST) {
+ WL_DBG(("PFN NET LOST event. Do Nothing \n"));
+ return 0;
+ }
+ WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count));
+ if (pfn_result->count > 0) {
+ int i;
+
+ memset(&request, 0x00, sizeof(struct cfg80211_scan_request));
+ memset(&ssid, 0x00, sizeof(ssid));
+ request.wiphy = wiphy;
+
+ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
+ - sizeof(wl_pfn_net_info_t));
+ channel = (struct ieee80211_channel *)kzalloc(
+ (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT),
+ GFP_KERNEL);
+ if (!channel) {
+ WL_ERR(("No memory"));
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ for (i = 0; i < pfn_result->count; i++) {
+ netinfo = &pnetinfo[i];
+ if (!netinfo) {
+ WL_ERR(("Invalid netinfo ptr. index:%d", i));
+ err = -EINVAL;
+ goto out_err;
+ }
+ WL_DBG(("SSID:%s Channel:%d \n",
+ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
+ /* PFN result doesn't have all the info which are required by the supplicant
+ * (For e.g IEs) Do a target Escan so that sched scan results are reported
+ * via wl_inform_single_bss in the required format. Escan does require the
+ * scan request in the form of cfg80211_scan_request. For timebeing, create
+ * cfg80211_scan_request one out of the received PNO event.
+ */
+ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID,
+ netinfo->pfnsubnet.SSID_len);
+ ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len;
+ request.n_ssids++;
+
+ channel_req = netinfo->pfnsubnet.channel;
+ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
+ : NL80211_BAND_5GHZ;
+ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
+ channel[i].band = band;
+ channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+ request.channels[i] = &channel[i];
+ request.n_channels++;
+ }
+
+ /* assign parsed ssid array */
+ if (request.n_ssids)
+ request.ssids = &ssid[0];
+
+ if (wl_get_drv_status_all(wl, SCANNING)) {
+ /* Abort any on-going scan */
+ wl_notify_escan_complete(wl, ndev, true, true);
+ }
+
+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
+ err = wl_cfgp2p_discover_enable_search(wl, false);
+ if (unlikely(err)) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
+ goto out_err;
+ }
+ }
+
+ wl_set_drv_status(wl, SCANNING, ndev);
+#if FULL_ESCAN_ON_PFN_NET_FOUND
+ err = wl_do_escan(wl, wiphy, ndev, NULL);
+#else
+ err = wl_do_escan(wl, wiphy, ndev, &request);
+#endif
+ if (err) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
+ goto out_err;
+ }
+ wl->sched_scan_running = TRUE;
+ }
+ else {
+ WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
+ }
+out_err:
+ if (channel)
+ kfree(channel);
+ return err;
+}
+#endif /* WL_SCHED_SCAN */
+
static void wl_init_conf(struct wl_conf *conf)
{
- s32 i = 0;
WL_DBG(("Enter \n"));
- for (i = 0; i <= VWDEV_CNT; i++) {
- conf->mode[i].type = -1;
- conf->mode[i].ndev = NULL;
- }
conf->frag_threshold = (u32)-1;
conf->rts_threshold = (u32)-1;
conf->retry_short = (u32)-1;
@@ -4940,13 +5547,14 @@ static void wl_init_conf(struct wl_conf *conf)
conf->tx_power = -1;
}
-static void wl_init_prof(struct wl_priv *wl)
+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev)
{
unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
- memset(wl->profile, 0, sizeof(struct wl_profile));
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+ memset(profile, 0, sizeof(struct wl_profile));
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
}
static void wl_init_event_handler(struct wl_priv *wl)
@@ -4969,7 +5577,9 @@ static void wl_init_event_handler(struct wl_priv *wl)
wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
-
+#ifdef PNO_SUPPORT
+ wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
+#endif /* PNO_SUPPORT */
}
static s32 wl_init_priv_mem(struct wl_priv *wl)
@@ -4985,23 +5595,13 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("wl_conf alloc failed\n"));
goto init_priv_mem_out;
}
- wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
- if (unlikely(!wl->profile)) {
- WL_ERR(("wl_profile alloc failed\n"));
- goto init_priv_mem_out;
- }
- wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
- if (unlikely(!wl->bss_info)) {
- WL_ERR(("Bss information alloc failed\n"));
- goto init_priv_mem_out;
- }
wl->scan_req_int =
(void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
if (unlikely(!wl->scan_req_int)) {
WL_ERR(("Scan req alloc failed\n"));
goto init_priv_mem_out;
}
- wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+ wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
if (unlikely(!wl->ioctl_buf)) {
WL_ERR(("Ioctl buf alloc failed\n"));
goto init_priv_mem_out;
@@ -5021,11 +5621,6 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("Iscan buf alloc failed\n"));
goto init_priv_mem_out;
}
- wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
- if (unlikely(!wl->fw)) {
- WL_ERR(("fw object alloc failed\n"));
- goto init_priv_mem_out;
- }
wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
if (unlikely(!wl->pmk_list)) {
WL_ERR(("pmk list alloc failed\n"));
@@ -5036,6 +5631,14 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("sta info alloc failed\n"));
goto init_priv_mem_out;
}
+ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL);
+ if (unlikely(!wl->afx_hdl)) {
+ WL_ERR(("afx hdl alloc failed\n"));
+ goto init_priv_mem_out;
+ } else {
+ init_completion(&wl->act_frm_scan);
+ INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler);
+ }
return 0;
init_priv_mem_out:
@@ -5048,12 +5651,8 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
{
kfree(wl->scan_results);
wl->scan_results = NULL;
- kfree(wl->bss_info);
- wl->bss_info = NULL;
kfree(wl->conf);
wl->conf = NULL;
- kfree(wl->profile);
- wl->profile = NULL;
kfree(wl->scan_req_int);
wl->scan_req_int = NULL;
kfree(wl->ioctl_buf);
@@ -5064,12 +5663,16 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
wl->extra_buf = NULL;
kfree(wl->iscan);
wl->iscan = NULL;
- kfree(wl->fw);
- wl->fw = NULL;
kfree(wl->pmk_list);
wl->pmk_list = NULL;
kfree(wl->sta_info);
wl->sta_info = NULL;
+ if (wl->afx_hdl) {
+ cancel_work_sync(&wl->afx_hdl->work);
+ kfree(wl->afx_hdl);
+ wl->afx_hdl = NULL;
+ }
+
if (wl->ap_info) {
kfree(wl->ap_info->wpa_ie);
kfree(wl->ap_info->rsn_ie);
@@ -5084,7 +5687,8 @@ static s32 wl_create_event_handler(struct wl_priv *wl)
int ret = 0;
WL_DBG(("Enter \n"));
- wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
+ /* Do not use DHD in cfg driver */
+ wl->event_tsk.thr_pid = -1;
PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
if (wl->event_tsk.thr_pid < 0)
ret = -ENOMEM;
@@ -5114,21 +5718,22 @@ static void wl_term_iscan(struct wl_priv *wl)
static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
{
struct wl_priv *wl = iscan_to_wl(iscan);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
unsigned long flags;
WL_DBG(("Enter \n"));
- if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
- wl_clr_drv_status(wl, SCANNING);
+ if (!wl_get_drv_status(wl, SCANNING, ndev)) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
WL_ERR(("Scan complete while device not scanning\n"));
return;
}
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
- wl_clr_drv_status(wl, SCANNING);
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+ wl_clr_drv_status(wl, SCANNING, ndev);
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
wl->iscan_kickstart = false;
}
@@ -5164,7 +5769,7 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list,
WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
- WL_ISCAN_BUF_MAX);
+ WL_ISCAN_BUF_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -5237,13 +5842,11 @@ static s32 wl_iscan_aborted(struct wl_priv *wl)
static s32 wl_iscan_thread(void *data)
{
- struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
struct wl_priv *wl = iscan_to_wl(iscan);
u32 status;
int err = 0;
- sched_setscheduler(current, SCHED_FIFO, &param);
allow_signal(SIGTERM);
status = WL_SCAN_RESULTS_PARTIAL;
while (likely(!down_interruptible(&iscan->sync))) {
@@ -5278,7 +5881,7 @@ static void wl_scan_timeout(unsigned long data)
if (wl->scan_request) {
WL_ERR(("timer expired\n"));
if (wl->escan_on)
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, wl->escan_info.ndev, true, false);
else
wl_notify_iscan_complete(wl_to_iscan(wl), true);
}
@@ -5324,21 +5927,109 @@ static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan)
iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
}
-static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
+static s32
+wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
+ unsigned long state,
+ void *ndev)
{
+ struct net_device *dev = ndev;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ WL_DBG(("Enter \n"));
+ if (!wdev || !wl || dev == wl_to_prmry_ndev(wl))
+ return NOTIFY_DONE;
+ switch (state) {
+ case NETDEV_UNREGISTER:
+ /* after calling list_del_rcu(&wdev->list) */
+ wl_dealloc_netinfo(wl, ndev);
+ break;
+ case NETDEV_GOING_DOWN:
+ /* At NETDEV_DOWN state, wdev_cleanup_work work will be called.
+ * In front of door, the function checks
+ * whether current scan is working or not.
+ * If the scanning is still working, wdev_cleanup_work call WARN_ON and
+ * make the scan done forcibly.
+ */
+ if (wl_get_drv_status(wl, SCANNING, dev)) {
+ if (wl->escan_on) {
+ wl_notify_escan_complete(wl, dev, true, true);
+ }
+ }
+ break;
+ }
+ return NOTIFY_DONE;
+}
+static struct notifier_block wl_cfg80211_netdev_notifier = {
+ .notifier_call = wl_cfg80211_netdev_notifier_call,
+};
+
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
+ struct net_device *ndev,
+ bool aborted, bool fw_abort)
+{
+ wl_scan_params_t *params = NULL;
+ s32 params_size = 0;
+ s32 err = BCME_OK;
unsigned long flags;
+ struct net_device *dev;
WL_DBG(("Enter \n"));
- wl_clr_drv_status(wl, SCANNING);
- if (wl->p2p_supported && p2p_on(wl))
- wl_clr_p2p_status(wl, SCANNING);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (wl->scan_request) {
+ if (wl->scan_request->dev == wl->p2p_net)
+ dev = wl_to_prmry_ndev(wl);
+ else
+ dev = wl->scan_request->dev;
+ }
+ else {
+ WL_ERR(("wl->scan_request is NULL may be internal scan."
+ "doing scan_abort for ndev %p primary %p p2p_net %p",
+ ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
+ dev = ndev;
+ }
+ if (fw_abort && !in_atomic()) {
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
+ if (params == NULL) {
+ WL_ERR(("scan params allocation failed \n"));
+ err = -ENOMEM;
+ } else {
+ /* Do a scan abort to stop the driver's scan engine */
+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
+ if (err < 0) {
+ WL_ERR(("scan abort failed \n"));
+ }
+ }
+ }
+ if (timer_pending(&wl->scan_timeout))
+ del_timer_sync(&wl->scan_timeout);
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+
+#ifdef WL_SCHED_SCAN
+ if (wl->sched_scan_req && !wl->scan_request) {
+ WL_DBG((" REPORTING SCHED SCAN RESULTS \n"));
+ if (aborted)
+ cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy);
+ else
+ cfg80211_sched_scan_results(wl->sched_scan_req->wiphy);
+ wl->sched_scan_running = FALSE;
+ wl->sched_scan_req = NULL;
+ }
+#endif /* WL_SCHED_SCAN */
+
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ if (p2p_is_on(wl))
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, dev);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+ if (params)
+ kfree(params);
+
+ return err;
}
static s32 wl_escan_handler(struct wl_priv *wl,
@@ -5353,11 +6044,21 @@ static s32 wl_escan_handler(struct wl_priv *wl,
wl_scan_results_t *list;
u32 bi_length;
u32 i;
+
WL_DBG((" enter event type : %d, status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
- if (!wl->escan_on &&
- !wl_get_drv_status(wl, SCANNING)) {
- WL_ERR(("escan is not ready \n"));
+ /* P2P SCAN is coming from primary interface */
+ if (wl_get_p2p_status(wl, SCANNING)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM))
+ ndev = wl->afx_hdl->dev;
+ else
+ ndev = wl->escan_info.ndev;
+
+ }
+ if (!ndev || !wl->escan_on ||
+ !wl_get_drv_status(wl, SCANNING, ndev)) {
+ WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n",
+ ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev)));
return err;
}
@@ -5382,77 +6083,114 @@ static s32 wl_escan_handler(struct wl_priv *wl,
WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
goto exit;
}
- list = (wl_scan_results_t *)wl->escan_info.escan_buf;
- if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
- WL_ERR(("Buffer is too small: ignoring\n"));
- goto exit;
+
+ if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
+ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
+ WL_ERR(("Ignoring IBSS result\n"));
+ goto exit;
+ }
}
-#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
- for (i = 0; i < list->count; i++) {
- bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
- : list->bss_info;
-
- if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
- CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
- bi->SSID_len == bss->SSID_len &&
- !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
- if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
- (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
- /* preserve max RSSI if the measurements are
- * both on-channel or both off-channel
- */
- bss->RSSI = MAX(bss->RSSI, bi->RSSI);
- } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
- (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
- /* preserve the on-channel rssi measurement
- * if the new measurement is off channel
- */
- bss->RSSI = bi->RSSI;
- bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
- }
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ if (!memcmp(bi->BSSID.octet,
+ wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) {
+ s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
+ WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel));
+ wl_clr_p2p_status(wl, SCANNING);
+ wl->afx_hdl->peer_chan = channel;
+ complete(&wl->act_frm_scan);
goto exit;
}
+
+ } else {
+ list = (wl_scan_results_t *)wl->escan_info.escan_buf;
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+ WL_ERR(("Buffer is too small: ignoring\n"));
+ goto exit;
+ }
+#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
+ for (i = 0; i < list->count; i++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+ : list->bss_info;
+
+ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
+ bi->SSID_len == bss->SSID_len &&
+ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
+ if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
+ (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
+ /* preserve max RSSI if the measurements are
+ * both on-channel or both off-channel
+ */
+ bss->RSSI = MAX(bss->RSSI, bi->RSSI);
+ } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
+ (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
+ /* preserve the on-channel rssi measurement
+ * if the new measurement is off channel
+ */
+ bss->RSSI = bi->RSSI;
+ bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
+ }
+
+ goto exit;
+ }
+ }
+ memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
+ list->version = dtoh32(bi->version);
+ list->buflen += bi_length;
+ list->count++;
+
}
- memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
- list->version = dtoh32(bi->version);
- list->buflen += bi_length;
- list->count++;
}
else if (status == WLC_E_STATUS_SUCCESS) {
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (likely(wl->scan_request)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ if (wl->afx_hdl->peer_chan == WL_INVALID)
+ complete(&wl->act_frm_scan);
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN COMPLETED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, false);
+ wl_notify_escan_complete(wl, ndev, false, false);
mutex_unlock(&wl->usr_sync);
}
}
else if (status == WLC_E_STATUS_ABORT) {
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (likely(wl->scan_request)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ wl_clr_p2p_status(wl, SCANNING);
+ if (wl->afx_hdl->peer_chan == WL_INVALID)
+ complete(&wl->act_frm_scan);
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN ABORTED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
mutex_unlock(&wl->usr_sync);
}
}
else {
WL_ERR(("unexpected Escan Event %d : abort\n", status));
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (likely(wl->scan_request)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ if (wl->afx_hdl->peer_chan == WL_INVALID)
+ complete(&wl->act_frm_scan);
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
mutex_unlock(&wl->usr_sync);
}
}
@@ -5493,16 +6231,11 @@ static s32 wl_init_scan(struct wl_priv *wl)
return err;
}
-static void wl_init_fw(struct wl_fw_ctrl *fw)
-{
- fw->status = 0;
-}
-
static s32 wl_init_priv(struct wl_priv *wl)
{
struct wiphy *wiphy = wl_to_wiphy(wl);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 err = 0;
- s32 i = 0;
wl->scan_request = NULL;
wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
@@ -5511,60 +6244,78 @@ static s32 wl_init_priv(struct wl_priv *wl)
wl->roam_on = false;
wl->iscan_kickstart = false;
wl->active_scan = true;
- wl->dongle_up = false;
wl->rf_blocked = false;
-
- for (i = 0; i < VWDEV_CNT; i++)
- wl->vwdev[i] = NULL;
-
- init_waitqueue_head(&wl->dongle_event_wait);
+ wl->deauth_reason = 0;
+ spin_lock_init(&wl->cfgdrv_lock);
+ mutex_init(&wl->ioctl_buf_sync);
+ init_waitqueue_head(&wl->netif_change_event);
wl_init_eq(wl);
err = wl_init_priv_mem(wl);
- if (unlikely(err))
+ if (err)
return err;
- if (unlikely(wl_create_event_handler(wl)))
+ if (wl_create_event_handler(wl))
return -ENOMEM;
wl_init_event_handler(wl);
mutex_init(&wl->usr_sync);
err = wl_init_scan(wl);
- if (unlikely(err))
+ if (err)
return err;
- wl_init_fw(wl->fw);
wl_init_conf(wl->conf);
- wl_init_prof(wl);
+ wl_init_prof(wl, ndev);
wl_link_down(wl);
+ DNGL_FUNC(dhd_cfg80211_init, (wl));
return err;
}
static void wl_deinit_priv(struct wl_priv *wl)
{
+ DNGL_FUNC(dhd_cfg80211_deinit, (wl));
wl_destroy_event_handler(wl);
- wl->dongle_up = false; /* dongle down */
wl_flush_eq(wl);
wl_link_down(wl);
del_timer_sync(&wl->scan_timeout);
wl_term_iscan(wl);
wl_deinit_priv_mem(wl);
+ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
}
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-s32 wl_cfg80211_sysctl_export_devaddr(void *data)
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+static s32 wl_cfg80211_attach_p2p(void)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ WL_TRACE(("Enter \n"));
+
+ if (wl_cfgp2p_register_ndev(wl) < 0) {
+ WL_ERR(("%s: P2P attach failed. \n", __func__));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static s32 wl_cfg80211_detach_p2p(void)
{
- /* Export the p2p_dev_addr via sysctl interface
- * so that wpa_supplicant can access it
- */
- dhd_pub_t *dhd = (dhd_pub_t *)data;
struct wl_priv *wl = wlcfg_drv_priv;
+ struct wireless_dev *wdev = wl->p2p_wdev;
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+ WL_DBG(("Enter \n"));
+ if (!wdev || !wl) {
+ WL_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
- sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet));
- sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet));
+ wl_cfgp2p_unregister_ndev(wl);
+
+ wl->p2p_wdev = NULL;
+ wl->p2p_net = NULL;
+ WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev));
+ kfree(wdev);
return 0;
}
-#endif /* CONFIG_SYSCTL */
+#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */
s32 wl_cfg80211_attach_post(struct net_device *ndev)
{
@@ -5576,75 +6327,107 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev)
return -ENODEV;
}
wl = wlcfg_drv_priv;
- if (wl && !wl_get_drv_status(wl, READY)) {
+ if (wl && !wl_get_drv_status(wl, READY, ndev)) {
if (wl->wdev &&
wl_cfgp2p_supported(wl, ndev)) {
+#if !defined(WL_ENABLE_P2P_IF)
wl->wdev->wiphy->interface_modes |=
(BIT(NL80211_IFTYPE_P2P_CLIENT)|
BIT(NL80211_IFTYPE_P2P_GO));
+#endif
if ((err = wl_cfgp2p_init_priv(wl)) != 0)
goto fail;
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
- wl_cfg80211_sysctl_export_devaddr(wl->pub);
-#endif
+
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ if (wl->p2p_net) {
+ /* Update MAC addr for p2p0 interface here. */
+ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
+ wl->p2p_net->dev_addr[0] |= 0x02;
+ printk("%s: p2p_dev_addr="MACSTR "\n",
+ wl->p2p_net->name, MAC2STR(wl->p2p_net->dev_addr));
+ } else {
+ WL_ERR(("p2p_net not yet populated."
+ " Couldn't update the MAC Address for p2p0 \n"));
+ return -ENODEV;
+ }
+#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */
+
wl->p2p_supported = true;
}
} else
return -ENODEV;
-
- wl_set_drv_status(wl, READY);
+ wl_set_drv_status(wl, READY, ndev);
fail:
return err;
}
+
s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
{
struct wireless_dev *wdev;
struct wl_priv *wl;
s32 err = 0;
+ struct device *dev;
WL_TRACE(("In\n"));
- if (unlikely(!ndev)) {
+ if (!ndev) {
WL_ERR(("ndev is invaild\n"));
return -ENODEV;
}
- WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
- wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(IS_ERR(wdev)))
- return -ENOMEM;
+ WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
+ dev = wl_cfg80211_get_parent_dev();
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return -ENOMEM;
+ }
+ err = wl_setup_wiphy(wdev, dev);
+ if (unlikely(err)) {
+ kfree(wdev);
+ return -ENOMEM;
+ }
wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
wl->wdev = wdev;
wl->pub = data;
-
+ INIT_LIST_HEAD(&wl->net_list);
ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
-
+ err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS);
+ if (err) {
+ WL_ERR(("Failed to alloc net_info (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
err = wl_init_priv(wl);
- if (unlikely(err)) {
+ if (err) {
WL_ERR(("Failed to init iwm_priv (%d)\n", err));
goto cfg80211_attach_out;
}
err = wl_setup_rfkill(wl, TRUE);
- if (unlikely(err)) {
+ if (err) {
WL_ERR(("Failed to setup rfkill %d\n", err));
goto cfg80211_attach_out;
}
-
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
- if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) {
- WL_ERR(("%s: sysctl register failed!! \n", __func__));
+ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+ if (err) {
+ WL_ERR(("Failed to register notifierl %d\n", err));
goto cfg80211_attach_out;
}
-#endif
#if defined(COEX_DHCP)
if (wl_cfg80211_btcoex_init(wl))
goto cfg80211_attach_out;
-#endif /* COEX_DHCP */
+#endif
wlcfg_drv_priv = wl;
+
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ err = wl_cfg80211_attach_p2p();
+ if (err)
+ goto cfg80211_attach_out;
+#endif
+
return err;
cfg80211_attach_out:
@@ -5653,7 +6436,7 @@ cfg80211_attach_out:
return err;
}
-void wl_cfg80211_detach(void)
+void wl_cfg80211_detach(void *para)
{
struct wl_priv *wl;
@@ -5663,19 +6446,21 @@ void wl_cfg80211_detach(void)
#if defined(COEX_DHCP)
wl_cfg80211_btcoex_deinit(wl);
-#endif /* COEX_DHCP */
+#endif
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
- if (wl_sysctl_hdr)
- unregister_sysctl_table(wl_sysctl_hdr);
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ wl_cfg80211_detach_p2p();
#endif
wl_setup_rfkill(wl, FALSE);
if (wl->p2p_supported)
wl_cfgp2p_deinit_priv(wl);
wl_deinit_priv(wl);
wlcfg_drv_priv = NULL;
- wl_clear_sdio_func();
+ wl_cfg80211_clear_parent_dev();
wl_free_wdev(wl);
+ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl",
+ * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!!
+ */
}
static void wl_wakeup_event(struct wl_priv *wl)
@@ -5686,6 +6471,42 @@ static void wl_wakeup_event(struct wl_priv *wl)
}
}
+static int wl_is_p2p_event(struct wl_event_q *e)
+{
+ switch (e->etype) {
+ /* We have to seperate out the P2P events received
+ * on primary interface so that it can be send up
+ * via p2p0 interface.
+ */
+ case WLC_E_P2P_PROBREQ_MSG:
+ case WLC_E_P2P_DISC_LISTEN_COMPLETE:
+ case WLC_E_ACTION_FRAME_RX:
+ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
+ case WLC_E_ACTION_FRAME_COMPLETE:
+
+ if (e->emsg.ifidx != 0) {
+ WL_TRACE(("P2P Event on Virtual I/F (ifidx:%d) \n",
+ e->emsg.ifidx));
+ /* We are only bothered about the P2P events received
+ * on primary interface. For rest of them return false
+ * so that it is sent over the interface corresponding
+ * to the ifidx.
+ */
+ return FALSE;
+ } else {
+ WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)."
+ " Sent it to p2p0 \n", e->emsg.ifidx));
+ return TRUE;
+ }
+ break;
+
+ default:
+ WL_TRACE(("NON-P2P Event %d on ifidx (ifidx:%d) \n",
+ e->etype, e->emsg.ifidx));
+ return FALSE;
+ }
+}
+
static s32 wl_event_handler(void *data)
{
struct net_device *netdev;
@@ -5694,6 +6515,7 @@ static s32 wl_event_handler(void *data)
tsk_ctl_t *tsk = (tsk_ctl_t *)data;
wl = (struct wl_priv *)tsk->parent;
+ DAEMONIZE("dhd_cfg80211_event");
complete(&tsk->completed);
while (down_interruptible (&tsk->sema) == 0) {
@@ -5702,7 +6524,15 @@ static s32 wl_event_handler(void *data)
break;
while ((e = wl_deq_event(wl))) {
WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
- netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+ /* All P2P device address related events comes on primary interface since
+ * there is no corresponding bsscfg for P2P interface. Map it to p2p0
+ * interface.
+ */
+ if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) {
+ netdev = wl->p2p_net;
+ } else {
+ netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+ }
if (!netdev)
netdev = wl_to_prmry_ndev(wl);
if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
@@ -5714,7 +6544,7 @@ static s32 wl_event_handler(void *data)
}
DHD_OS_WAKE_UNLOCK(wl->pub);
}
- WL_DBG(("%s was terminated\n", __func__));
+ WL_ERR(("%s was terminated\n", __func__));
complete_and_exit(&tsk->completed, 0);
return 0;
}
@@ -5731,9 +6561,6 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
#endif /* (WL_DBG_LEVEL > 0) */
- if (event_type == WLC_E_PFN_NET_FOUND)
- WL_ERR((" PNO Event\n"));
-
if (likely(!wl_enq_event(wl, ndev, event_type, e, data)))
wl_wakeup_event(wl);
}
@@ -5818,22 +6645,7 @@ static void wl_put_event(struct wl_event_q *e)
kfree(e);
}
-void wl_cfg80211_set_sdio_func(void *func)
-{
- cfg80211_sdio_func = (struct sdio_func *)func;
-}
-
-static void wl_clear_sdio_func(void)
-{
- cfg80211_sdio_func = NULL;
-}
-
-struct sdio_func *wl_cfg80211_get_sdio_func(void)
-{
- return cfg80211_sdio_func;
-}
-
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
{
s32 infra = 0;
s32 err = 0;
@@ -5870,11 +6682,12 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp
return err;
}
- set_mode_by_netdev(wl, ndev, mode);
+ wl_set_mode_by_netdev(wl, ndev, mode);
return 0;
}
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
{
s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
@@ -5887,7 +6700,7 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo
err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("Get event_msgs error (%d)\n", err));
- goto dongle_eventmsg_out;
+ goto eventmsg_out;
}
memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
if (add) {
@@ -5900,389 +6713,103 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo
err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("Set event_msgs error (%d)\n", err));
- goto dongle_eventmsg_out;
+ goto eventmsg_out;
}
-dongle_eventmsg_out:
+eventmsg_out:
return err;
}
-
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
-{
-
- s32 err = 0;
-
- return err;
-}
-
-static s32 wl_dongle_up(struct net_device *ndev, u32 up)
-{
- s32 err = 0;
-
- err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
- if (unlikely(err)) {
- WL_ERR(("WLC_UP error (%d)\n", err));
- }
- return err;
-}
-
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
+s32 wl_update_wiphybands(struct wl_priv *wl)
{
+ struct wiphy *wiphy;
+ u32 bandlist[3];
+ u32 nband = 0;
+ u32 i = 0;
s32 err = 0;
-
- WL_TRACE(("In\n"));
- err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
+ int nmode = 0;
+ int bw_40 = 0;
+ int index = 0;
+
+ WL_DBG(("Entry"));
+ memset(bandlist, 0, sizeof(bandlist));
+ err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
+ sizeof(bandlist), false);
if (unlikely(err)) {
- WL_ERR(("WLC_SET_PM error (%d)\n", err));
+ WL_ERR(("error read bandlist (%d)\n", err));
+ return err;
}
- return err;
-}
-
-static s32
-wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
-{
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s32 err = 0;
+ wiphy = wl_to_wiphy(wl);
+ nband = bandlist[0];
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+ wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
- /* Match Host and Dongle rx alignment */
- bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode);
if (unlikely(err)) {
- WL_ERR(("txglomalign error (%d)\n", err));
- goto dongle_glom_out;
+ WL_ERR(("error reading nmode (%d)\n", err));
}
- /* disable glom option per default */
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (unlikely(err)) {
- WL_ERR(("txglom error (%d)\n", err));
- goto dongle_glom_out;
- }
-dongle_glom_out:
- return err;
-}
-
-static s32
-wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
-{
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s32 err = 0;
-
- /* Setup timeout if Beacons are lost and roam is off to report link down */
- if (roamvar) {
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ else {
+ /* For nmodeonly check bw cap */
+ err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40);
if (unlikely(err)) {
- WL_ERR(("bcn_timeout error (%d)\n", err));
- goto dongle_rom_out;
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
}
}
- /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (unlikely(err)) {
- WL_ERR(("roam_off error (%d)\n", err));
- goto dongle_rom_out;
- }
-dongle_rom_out:
- return err;
-}
-static s32
-wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time)
-{
- s32 err = 0;
-
- err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
- sizeof(scan_assoc_time), true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("Scan assoc time is not supported\n"));
- } else {
- WL_ERR(("Scan assoc time error (%d)\n", err));
- }
- goto dongle_scantime_out;
- }
- err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
- sizeof(scan_unassoc_time), true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("Scan unassoc time is not supported\n"));
- } else {
- WL_ERR(("Scan unassoc time error (%d)\n", err));
+ for (i = 1; i <= nband && i < sizeof(bandlist)/sizeof(u32); i++) {
+ index = -1;
+ if (bandlist[i] == WLC_BAND_5G) {
+ wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &__wl_band_5ghz_a;
+ index = IEEE80211_BAND_5GHZ;
+ } else if (bandlist[i] == WLC_BAND_2G) {
+ wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &__wl_band_2ghz;
+ index = IEEE80211_BAND_2GHZ;
}
- goto dongle_scantime_out;
- }
-
-dongle_scantime_out:
- return err;
-}
-
-static s32
-wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
-{
- /* Room for "event_msgs" + '\0' + bitvec */
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s32 err = 0;
-
- /* Set ARP offload */
- bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (err) {
- if (err == -EOPNOTSUPP)
- WL_INFO(("arpoe is not supported\n"));
- else
- WL_ERR(("arpoe error (%d)\n", err));
-
- goto dongle_offload_out;
- }
- bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (err) {
- if (err == -EOPNOTSUPP)
- WL_INFO(("arp_ol is not supported\n"));
- else
- WL_ERR(("arp_ol error (%d)\n", err));
-
- goto dongle_offload_out;
- }
-
-dongle_offload_out:
- return err;
-}
-
-static s32 wl_pattern_atoh(s8 *src, s8 *dst)
-{
- int i;
- if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
- WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
- return -1;
- }
- src = src + 2; /* Skip past 0x */
- if (strlen(src) % 2 != 0) {
- WL_ERR(("Mask invalid format. Needs to be of even length\n"));
- return -1;
- }
- for (i = 0; *src != '\0'; i++) {
- char num[3];
- strncpy(num, src, 2);
- num[2] = '\0';
- dst[i] = (u8) simple_strtoul(num, NULL, 16);
- src += 2;
- }
- return i;
-}
-
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
-{
- /* Room for "event_msgs" + '\0' + bitvec */
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- const s8 *str;
- struct wl_pkt_filter pkt_filter;
- struct wl_pkt_filter *pkt_filterp;
- s32 buf_len;
- s32 str_len;
- u32 mask_size;
- u32 pattern_size;
- s8 buf[256];
- s32 err = 0;
-
- /* add a default packet filter pattern */
- str = "pkt_filter_add";
- str_len = strlen(str);
- strncpy(buf, str, str_len);
- buf[str_len] = '\0';
- buf_len = str_len + 1;
-
- pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
-
- /* Parse packet filter id. */
- pkt_filter.id = htod32(100);
-
- /* Parse filter polarity. */
- pkt_filter.negate_match = htod32(0);
-
- /* Parse filter type. */
- pkt_filter.type = htod32(0);
-
- /* Parse pattern filter offset. */
- pkt_filter.u.pattern.offset = htod32(0);
-
- /* Parse pattern filter mask. */
- mask_size = htod32(wl_pattern_atoh("0xff",
- (char *)pkt_filterp->u.pattern.
- mask_and_pattern));
-
- /* Parse pattern filter pattern. */
- pattern_size = htod32(wl_pattern_atoh("0x00",
- (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
-
- if (mask_size != pattern_size) {
- WL_ERR(("Mask and pattern not the same size\n"));
- err = -EINVAL;
- goto dongle_filter_out;
- }
-
- pkt_filter.u.pattern.size_bytes = mask_size;
- buf_len += WL_PKT_FILTER_FIXED_LEN;
- buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
- /* Keep-alive attributes are set in local
- * variable (keep_alive_pkt), and
- * then memcpy'ed into buffer (keep_alive_pktp) since there is no
- * guarantee that the buffer is properly aligned.
- */
- memcpy((char *)pkt_filterp, &pkt_filter,
- WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
-
- err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("filter not supported\n"));
- } else {
- WL_ERR(("filter (%d)\n", err));
+ if ((index >= 0) && nmode) {
+ wiphy->bands[index]->ht_cap.cap =
+ IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 |
+ IEEE80211_HT_CAP_MAX_AMSDU;
+ wiphy->bands[index]->ht_cap.ht_supported = TRUE;
+ wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
}
- goto dongle_filter_out;
- }
- /* set mode to allow pattern */
- bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("filter_mode not supported\n"));
- } else {
- WL_ERR(("filter_mode (%d)\n", err));
+ if ((index >= 0) && bw_40) {
+ wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
}
- goto dongle_filter_out;
}
-dongle_filter_out:
+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
return err;
}
-#endif /* !EMBEDDED_PLATFORM */
-s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
+static s32 __wl_cfg80211_up(struct wl_priv *wl)
{
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN 32
-#endif
- struct net_device *ndev;
- struct wireless_dev *wdev;
s32 err = 0;
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
- WL_TRACE(("In\n"));
- if (wl->dongle_up) {
- WL_ERR(("Dongle is already up\n"));
- return err;
- }
+ WL_DBG(("In\n"));
- ndev = wl_to_prmry_ndev(wl);
- wdev = ndev->ieee80211_ptr;
- if (need_lock)
- rtnl_lock();
-#ifndef EMBEDDED_PLATFORM
- err = wl_dongle_up(ndev, 0);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_up failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_country(ndev, 0);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_country failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_power(ndev, PM_FAST);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_power failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_glom failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_roam failed\n"));
- goto default_conf_out;
- }
- wl_dongle_scantime(ndev, 40, 80);
- wl_dongle_offload(ndev, 1, 0xf);
- wl_dongle_filter(ndev, 1);
-#endif /* !EMBEDDED_PLATFORM */
+ err = dhd_config_dongle(wl, false);
+ if (unlikely(err))
+ return err;
- err = wl_dongle_mode(wl, ndev, wdev->iftype);
+ err = wl_config_ifmode(wl, ndev, wdev->iftype);
if (unlikely(err && err != -EINPROGRESS)) {
- WL_ERR(("wl_dongle_mode failed\n"));
- goto default_conf_out;
+ WL_ERR(("wl_config_ifmode failed\n"));
}
- err = wl_dongle_probecap(wl);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_probecap failed\n"));
- goto default_conf_out;
- }
-
- /* -EINPROGRESS: Call commit handler */
-
-default_conf_out:
- if (need_lock)
- rtnl_unlock();
-
- wl->dongle_up = true;
-
- return err;
-
-}
-
-static s32 wl_update_wiphybands(struct wl_priv *wl)
-{
- struct wiphy *wiphy;
- s8 phylist_buf[128];
- s8 *phy;
- s32 err = 0;
-
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
- sizeof(phylist_buf), false);
+ err = wl_update_wiphybands(wl);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- return err;
+ WL_ERR(("wl_update_wiphybands failed\n"));
}
- phy = phylist_buf;
- for (; *phy; phy++) {
- if (*phy == 'a' || *phy == 'n') {
- wiphy = wl_to_wiphy(wl);
- wiphy->bands[IEEE80211_BAND_5GHZ] =
- &__wl_band_5ghz_a;
- }
- }
- return err;
-}
-
-static s32 __wl_cfg80211_up(struct wl_priv *wl)
-{
- s32 err = 0;
-
- WL_TRACE(("In\n"));
- wl_debugfs_add_netdev_params(wl);
- err = wl_config_dongle(wl, false);
- if (unlikely(err))
- return err;
- dhd_monitor_init(wl->pub);
- wl_invoke_iscan(wl);
- wl_set_drv_status(wl, READY);
+ err = dhd_monitor_init(wl->pub);
+ err = wl_invoke_iscan(wl);
+ wl_set_drv_status(wl, READY, ndev);
return err;
}
@@ -6290,52 +6817,65 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
{
s32 err = 0;
unsigned long flags;
+ struct net_info *iter, *next;
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+#ifdef WL_ENABLE_P2P_IF
+ struct wiphy *wiphy = wl_to_prmry_ndev(wl)->ieee80211_ptr->wiphy;
+ struct net_device *p2p_net = wl->p2p_net;
+#endif
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
/* Check if cfg80211 interface is already down */
- if (!wl_get_drv_status(wl, READY))
+ if (!wl_get_drv_status(wl, READY, ndev))
return err; /* it is even not ready */
-
- wl_set_drv_status(wl, SCAN_ABORTING);
+ for_each_ndev(wl, iter, next)
+ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
wl_term_iscan(wl);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
- wl_clr_drv_status(wl, READY);
- wl_clr_drv_status(wl, SCANNING);
- wl_clr_drv_status(wl, SCAN_ABORTING);
- wl_clr_drv_status(wl, CONNECTING);
- wl_clr_drv_status(wl, CONNECTED);
- wl_clr_drv_status(wl, DISCONNECTING);
- if (wl_get_drv_status(wl, AP_CREATED)) {
- wl_clr_drv_status(wl, AP_CREATED);
- wl_clr_drv_status(wl, AP_CREATING);
+ for_each_ndev(wl, iter, next) {
+ wl_clr_drv_status(wl, READY, iter->ndev);
+ wl_clr_drv_status(wl, SCANNING, iter->ndev);
+ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
+ wl_clr_drv_status(wl, CONNECTING, iter->ndev);
+ wl_clr_drv_status(wl, CONNECTED, iter->ndev);
+ wl_clr_drv_status(wl, DISCONNECTING, iter->ndev);
+ wl_clr_drv_status(wl, AP_CREATED, iter->ndev);
+ wl_clr_drv_status(wl, AP_CREATING, iter->ndev);
}
wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
NL80211_IFTYPE_STATION;
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
-
- wl->dongle_up = false;
+#ifdef WL_ENABLE_P2P_IF
+ wiphy->interface_modes = (wiphy->interface_modes)
+ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO)));
+ if ((p2p_net) && (p2p_net->flags & IFF_UP)) {
+ /* p2p0 interface is still UP. Bring it down */
+ p2p_net->flags &= ~IFF_UP;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+
+ DNGL_FUNC(dhd_cfg80211_down, (wl));
wl_flush_eq(wl);
wl_link_down(wl);
if (wl->p2p_supported)
wl_cfgp2p_down(wl);
dhd_monitor_uninit();
- wl_debugfs_remove_netdev(wl);
-
return err;
}
-s32 wl_cfg80211_up(void)
+s32 wl_cfg80211_up(void *para)
{
struct wl_priv *wl;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
@@ -6343,17 +6883,16 @@ s32 wl_cfg80211_up(void)
if (err)
WL_ERR(("__wl_cfg80211_up failed\n"));
mutex_unlock(&wl->usr_sync);
-
return err;
}
-/* Private Event to Supplicant with indication that FW hangs */
+/* Private Event to Supplicant with indication that chip hangs */
int wl_cfg80211_hang(struct net_device *dev, u16 reason)
{
struct wl_priv *wl;
wl = wlcfg_drv_priv;
- WL_ERR(("In : FW crash Eventing\n"));
+ WL_ERR(("In : chip crash eventing\n"));
cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
if (wl != NULL) {
wl_link_down(wl);
@@ -6361,12 +6900,12 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason)
return 0;
}
-s32 wl_cfg80211_down(void)
+s32 wl_cfg80211_down(void *para)
{
struct wl_priv *wl;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
err = __wl_cfg80211_down(wl);
@@ -6375,84 +6914,79 @@ s32 wl_cfg80211_down(void)
return err;
}
-static s32 wl_dongle_probecap(struct wl_priv *wl)
-{
- s32 err = 0;
-
- err = wl_update_wiphybands(wl);
- if (unlikely(err))
- return err;
-
- return err;
-}
-
-static void *wl_read_prof(struct wl_priv *wl, s32 item)
+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item)
{
unsigned long flags;
void *rptr = NULL;
+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (!profile)
+ return NULL;
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
switch (item) {
case WL_PROF_SEC:
- rptr = &wl->profile->sec;
+ rptr = &profile->sec;
break;
case WL_PROF_ACT:
- rptr = &wl->profile->active;
+ rptr = &profile->active;
break;
case WL_PROF_BSSID:
- rptr = &wl->profile->bssid;
+ rptr = profile->bssid;
break;
case WL_PROF_SSID:
- rptr = &wl->profile->ssid;
+ rptr = &profile->ssid;
break;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
if (!rptr)
WL_ERR(("invalid item (%d)\n", item));
return rptr;
}
static s32
-wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
- s32 item)
+wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, s32 item)
{
s32 err = 0;
struct wlc_ssid *ssid;
unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (!profile)
+ return WL_INVALID;
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
switch (item) {
case WL_PROF_SSID:
ssid = (wlc_ssid_t *) data;
- memset(wl->profile->ssid.SSID, 0,
- sizeof(wl->profile->ssid.SSID));
- memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
- wl->profile->ssid.SSID_len = ssid->SSID_len;
+ memset(profile->ssid.SSID, 0,
+ sizeof(profile->ssid.SSID));
+ memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
+ profile->ssid.SSID_len = ssid->SSID_len;
break;
case WL_PROF_BSSID:
if (data)
- memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
+ memcpy(profile->bssid, data, ETHER_ADDR_LEN);
else
- memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
+ memset(profile->bssid, 0, ETHER_ADDR_LEN);
break;
case WL_PROF_SEC:
- memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
+ memcpy(&profile->sec, data, sizeof(profile->sec));
break;
case WL_PROF_ACT:
- wl->profile->active = *(bool *)data;
+ profile->active = *(bool *)data;
break;
case WL_PROF_BEACONINT:
- wl->profile->beacon_interval = *(u16 *)data;
+ profile->beacon_interval = *(u16 *)data;
break;
case WL_PROF_DTIMPERIOD:
- wl->profile->dtim_period = *(u8 *)data;
+ profile->dtim_period = *(u8 *)data;
break;
default:
WL_ERR(("unsupported item (%d)\n", item));
err = -EOPNOTSUPP;
break;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
return err;
}
@@ -6469,7 +7003,7 @@ void wl_cfg80211_dbg_level(u32 level)
static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev)
{
- return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
+ return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
}
static __used bool wl_is_ibssstarter(struct wl_priv *wl)
@@ -6580,114 +7114,28 @@ static void wl_delay(u32 ms)
}
}
-s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
-{
- const struct firmware *fw_entry;
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
-
- fw_entry = wl->fw->fw_entry;
-
- if (fw_entry->size < wl->fw->ptr + size)
- size = fw_entry->size - wl->fw->ptr;
-
- memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
- wl->fw->ptr += size;
- return size;
-}
-
-void wl_cfg80211_release_fw(void)
-{
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
- release_firmware(wl->fw->fw_entry);
- wl->fw->ptr = 0;
-}
-
-void *wl_cfg80211_request_fw(s8 *file_name)
-{
- struct wl_priv *wl;
- const struct firmware *fw_entry = NULL;
- s32 err = 0;
-
- WL_TRACE(("In\n"));
- WL_DBG(("file name : \"%s\"\n", file_name));
- wl = wlcfg_drv_priv;
-
- if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
- err = request_firmware(&wl->fw->fw_entry, file_name,
- &wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(err)) {
- WL_ERR(("Could not download fw (%d)\n", err));
- goto req_fw_out;
- }
- set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
- fw_entry = wl->fw->fw_entry;
- if (fw_entry) {
- WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
- fw_entry->data));
- }
- } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
- err = request_firmware(&wl->fw->fw_entry, file_name,
- &wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(err)) {
- WL_ERR(("Could not download nvram (%d)\n", err));
- goto req_fw_out;
- }
- set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
- fw_entry = wl->fw->fw_entry;
- if (fw_entry) {
- WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
- fw_entry->data));
- }
- } else {
- WL_DBG(("Downloading already done. Nothing to do more\n"));
- err = -EPERM;
- }
-
-req_fw_out:
- if (unlikely(err)) {
- return NULL;
- }
- wl->fw->ptr = 0;
- return (void *)fw_entry->data;
-}
-
-s8 *wl_cfg80211_get_fwname(void)
-{
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
- strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
- return wl->fw->fw_name;
-}
-
-s8 *wl_cfg80211_get_nvramname(void)
-{
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
- strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
- return wl->fw->nvram_name;
-}
-
s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
{
- struct wl_priv *wl;
- dhd_pub_t *dhd_pub;
+ struct wl_priv *wl = wlcfg_drv_priv;
struct ether_addr p2pif_addr;
+ struct ether_addr primary_mac;
- wl = wlcfg_drv_priv;
- dhd_pub = (dhd_pub_t *)wl->pub;
- wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
+ if (!wl->p2p)
+ return -1;
+ if (!p2p_is_on(wl)) {
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr);
+ } else {
+ memcpy(p2pdev_addr->octet,
+ wl->p2p->dev_addr.octet, ETHER_ADDR_LEN);
+ }
return 0;
}
s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
{
struct wl_priv *wl;
+
wl = wlcfg_drv_priv;
return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
@@ -6721,8 +7169,8 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
if (wl->p2p && wl->p2p->vif_created) {
ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
- } else if (wl_get_drv_status(wl, AP_CREATING) ||
- wl_get_drv_status(wl, AP_CREATED)) {
+ } else if (wl_get_drv_status(wl, AP_CREATING, net) ||
+ wl_get_drv_status(wl, AP_CREATED, net)) {
ndev = net;
bssidx = 0;
}
@@ -6745,69 +7193,6 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
return ret;
}
-static __used void wl_dongle_poweron(struct wl_priv *wl)
-{
- WL_DBG(("Enter \n"));
- dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
-
-#if defined(BCMLXSDMMC)
- sdioh_start(NULL, 0);
-#endif
-#if defined(BCMLXSDMMC)
- sdioh_start(NULL, 1);
-#endif
- wl_cfg80211_resume(wl_to_wiphy(wl));
-}
-
-static __used void wl_dongle_poweroff(struct wl_priv *wl)
-{
- WL_DBG(("Enter \n"));
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
- wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
-#else
- wl_cfg80211_suspend(wl_to_wiphy(wl));
-#endif
-
-#if defined(BCMLXSDMMC)
- sdioh_stop(NULL);
-#endif
- /* clean up dtim_skip setting */
- dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
-}
-
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
-{
- char buf[10+IFNAMSIZ];
- struct dentry *fd;
- s32 err = 0;
-
- WL_TRACE(("In\n"));
- sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name);
- wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
-
- fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
- (u16 *)&wl->profile->beacon_interval);
- if (!fd) {
- err = -ENOMEM;
- goto err_out;
- }
-
- fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
- (u8 *)&wl->profile->dtim_period);
- if (!fd) {
- err = -ENOMEM;
- goto err_out;
- }
-
-err_out:
- return err;
-}
-
-static void wl_debugfs_remove_netdev(struct wl_priv *wl)
-{
- WL_DBG(("Enter \n"));
-}
-
static const struct rfkill_ops wl_rfkill_ops = {
.set_block = wl_rfkill_set
};
@@ -6836,7 +7221,7 @@ static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
return -EINVAL;
if (setup) {
wl->rfkill = rfkill_alloc("brcmfmac-wifi",
- &wl_cfg80211_get_sdio_func()->dev,
+ wl_cfg80211_get_parent_dev(),
RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
if (!wl->rfkill) {
@@ -6862,471 +7247,42 @@ err_out:
return err;
}
-#if defined(COEX_DHCP)
-/*
- * get named driver variable to uint register value and return error indication
- * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
- */
-static int
-dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
- uint reg, int *retval)
+struct device *wl_cfg80211_get_parent_dev(void)
{
- union {
- char buf[WLC_IOCTL_SMLEN];
- int val;
- } var;
- int error;
-
- bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
- (char *)(&var), sizeof(var.buf));
- error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
-
- *retval = dtoh32(var.val);
- return (error);
+ return cfg80211_parent_dev;
}
-static int
-dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+void wl_cfg80211_set_parent_dev(void *dev)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
- char ioctlbuf[1024];
-#else
- static char ioctlbuf[1024];
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
-
- bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
-
- return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
-}
-/*
-get named driver variable to uint register value and return error indication
-calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
-*/
-static int
-dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
-{
- char reg_addr[8];
-
- memset(reg_addr, 0, sizeof(reg_addr));
- memcpy((char *)&reg_addr[0], (char *)addr, 4);
- memcpy((char *)&reg_addr[4], (char *)val, 4);
-
- return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+ cfg80211_parent_dev = dev;
}
-static bool btcoex_is_sco_active(struct net_device *dev)
+static void wl_cfg80211_clear_parent_dev(void)
{
- int ioc_res = 0;
- bool res = FALSE;
- int sco_id_cnt = 0;
- int param27;
- int i;
-
- for (i = 0; i < 12; i++) {
-
- ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
-
- WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
- __FUNCTION__, i, param27));
-
- if (ioc_res < 0) {
- WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
- break;
- }
-
- if ((param27 & 0x6) == 2) { /* count both sco & esco */
- sco_id_cnt++;
- }
-
- if (sco_id_cnt > 2) {
- WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
- __FUNCTION__, sco_id_cnt, i));
- res = TRUE;
- break;
- }
-
- msleep(5);
- }
-
- return res;
+ cfg80211_parent_dev = NULL;
}
-#if defined(BT_DHCP_eSCO_FIX)
-/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
-static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac)
{
- static bool saved_status = FALSE;
-
- char buf_reg50va_dhcp_on[8] =
- { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
- char buf_reg51va_dhcp_on[8] =
- { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- char buf_reg64va_dhcp_on[8] =
- { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- char buf_reg65va_dhcp_on[8] =
- { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- char buf_reg71va_dhcp_on[8] =
- { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- uint32 regaddr;
- static uint32 saved_reg50;
- static uint32 saved_reg51;
- static uint32 saved_reg64;
- static uint32 saved_reg65;
- static uint32 saved_reg71;
-
- if (trump_sco) {
- /* this should reduce eSCO agressive retransmit
- * w/o breaking it
- */
-
- /* 1st save current */
- WL_TRACE(("Do new SCO/eSCO coex algo {save &"
- "override}\n"));
- if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
- saved_status = TRUE;
- WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
- "0x%x 0x%x 0x%x 0x%x 0x%x\n",
- __FUNCTION__, saved_reg50, saved_reg51,
- saved_reg64, saved_reg65, saved_reg71));
- } else {
- WL_ERR((":%s: save btc_params failed\n",
- __FUNCTION__));
- saved_status = FALSE;
- return -1;
- }
-
- WL_TRACE(("override with [50,51,64,65,71]:"
- "0x%x 0x%x 0x%x 0x%x 0x%x\n",
- *(u32 *)(buf_reg50va_dhcp_on+4),
- *(u32 *)(buf_reg51va_dhcp_on+4),
- *(u32 *)(buf_reg64va_dhcp_on+4),
- *(u32 *)(buf_reg65va_dhcp_on+4),
- *(u32 *)(buf_reg71va_dhcp_on+4)));
-
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg50va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg51va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg64va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg65va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg71va_dhcp_on[0], 8);
-
- saved_status = TRUE;
- } else if (saved_status) {
- /* restore previously saved bt params */
- WL_TRACE(("Do new SCO/eSCO coex algo {save &"
- "override}\n"));
-
- regaddr = 50;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg50);
- regaddr = 51;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg51);
- regaddr = 64;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg64);
- regaddr = 65;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg65);
- regaddr = 71;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg71);
-
- WL_TRACE(("restore bt_params[50,51,64,65,71]:"
- "0x%x 0x%x 0x%x 0x%x 0x%x\n",
- saved_reg50, saved_reg51, saved_reg64,
- saved_reg65, saved_reg71));
-
- saved_status = FALSE;
- } else {
- WL_ERR((":%s att to restore not saved BTCOEX params\n",
- __FUNCTION__));
- return -1;
- }
- return 0;
-}
-#endif /* BT_DHCP_eSCO_FIX */
-
-static void
-wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
-{
-#if defined(BT_DHCP_USE_FLAGS)
- char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
- char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
-#endif
-
-#if defined(BT_DHCP_eSCO_FIX)
- /* set = 1, save & turn on 0 - off & restore prev settings */
- set_btc_esco_params(dev, set);
-#endif
-
-#if defined(BT_DHCP_USE_FLAGS)
- WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
- if (set == TRUE)
- /* Forcing bt_flag7 */
- dev_wlc_bufvar_set(dev, "btc_flags",
- (char *)&buf_flag7_dhcp_on[0],
- sizeof(buf_flag7_dhcp_on));
- else
- /* Restoring default bt flag7 */
- dev_wlc_bufvar_set(dev, "btc_flags",
- (char *)&buf_flag7_default[0],
- sizeof(buf_flag7_default));
-#endif
-}
-
-static void wl_cfg80211_bt_timerfunc(ulong data)
-{
- struct btcoex_info *bt_local = (struct btcoex_info *)data;
- WL_TRACE(("%s\n", __FUNCTION__));
- bt_local->timer_on = 0;
- schedule_work(&bt_local->work);
-}
-
-static void wl_cfg80211_bt_handler(struct work_struct *work)
-{
- struct btcoex_info *btcx_inf;
-
- btcx_inf = container_of(work, struct btcoex_info, work);
-
- if (btcx_inf->timer_on) {
- btcx_inf->timer_on = 0;
- del_timer_sync(&btcx_inf->timer);
- }
-
- switch (btcx_inf->bt_state) {
- case BT_DHCP_START:
- /* DHCP started
- * provide OPPORTUNITY window to get DHCP address
- */
- WL_TRACE(("%s bt_dhcp stm: started \n",
- __FUNCTION__));
- btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
- mod_timer(&btcx_inf->timer,
- jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
- btcx_inf->timer_on = 1;
- break;
-
- case BT_DHCP_OPPR_WIN:
- if (btcx_inf->dhcp_done) {
- WL_TRACE(("%s DHCP Done before T1 expiration\n",
- __FUNCTION__));
- goto btc_coex_idle;
- }
-
- /* DHCP is not over yet, start lowering BT priority
- * enforce btc_params + flags if necessary
- */
- WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
- BT_DHCP_OPPR_WIN_TIME));
- if (btcx_inf->dev)
- wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
- btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
- mod_timer(&btcx_inf->timer,
- jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
- btcx_inf->timer_on = 1;
- break;
-
- case BT_DHCP_FLAG_FORCE_TIMEOUT:
- if (btcx_inf->dhcp_done) {
- WL_TRACE(("%s DHCP Done before T2 expiration\n",
- __FUNCTION__));
- } else {
- /* Noo dhcp during T1+T2, restore BT priority */
- WL_TRACE(("%s DHCP wait interval T2:%d"
- "msec expired\n", __FUNCTION__,
- BT_DHCP_FLAG_FORCE_TIME));
- }
-
- /* Restoring default bt priority */
- if (btcx_inf->dev)
- wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
-btc_coex_idle:
- btcx_inf->bt_state = BT_DHCP_IDLE;
- btcx_inf->timer_on = 0;
- break;
-
- default:
- WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
- btcx_inf->bt_state));
- if (btcx_inf->dev)
- wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
- btcx_inf->bt_state = BT_DHCP_IDLE;
- btcx_inf->timer_on = 0;
- break;
- }
-
- net_os_wake_unlock(btcx_inf->dev);
+ wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL,
+ 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
+ memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN);
}
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+int wl_cfg80211_do_driver_init(struct net_device *net)
{
- struct btcoex_info *btco_inf = NULL;
+ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
- btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
- if (!btco_inf)
- return -ENOMEM;
-
- btco_inf->bt_state = BT_DHCP_IDLE;
- btco_inf->ts_dhcp_start = 0;
- btco_inf->ts_dhcp_ok = 0;
- /* Set up timer for BT */
- btco_inf->timer_ms = 10;
- init_timer(&btco_inf->timer);
- btco_inf->timer.data = (ulong)btco_inf;
- btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
-
- btco_inf->dev = wl->wdev->netdev;
+ if (!wl || !wl->wdev)
+ return -EINVAL;
- INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+ if (dhd_do_driver_init(wl->wdev->netdev) < 0)
+ return -1;
- wl->btcoex_info = btco_inf;
return 0;
}
-static void
-wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+void wl_cfg80211_enable_trace(int level)
{
- if (!wl->btcoex_info)
- return;
-
- if (!wl->btcoex_info->timer_on) {
- wl->btcoex_info->timer_on = 0;
- del_timer_sync(&wl->btcoex_info->timer);
- }
-
- cancel_work_sync(&wl->btcoex_info->work);
-
- kfree(wl->btcoex_info);
- wl->btcoex_info = NULL;
-}
-#endif /* COEX_DHCP */
-
-int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
-{
- char powermode_val = 0;
- char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
- char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
- char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
-
- uint32 regaddr;
- static uint32 saved_reg66;
- static uint32 saved_reg41;
- static uint32 saved_reg68;
- static bool saved_status = FALSE;
-
-#ifdef COEX_DHCP
- char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
- struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
-#endif /* COEX_DHCP */
-
- /* Figure out powermode 1 or o command */
- strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
-
- if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
-
- WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
-
- /* Retrieve and saved orig regs value */
- if ((saved_status == FALSE) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
- saved_status = TRUE;
- WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
- saved_reg66, saved_reg41, saved_reg68));
-
- /* Disable PM mode during dhpc session */
-
- /* Disable PM mode during dhpc session */
-#ifdef COEX_DHCP
- /* Start BT timer only for SCO connection */
- if (btcoex_is_sco_active(dev)) {
- /* btc_params 66 */
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg66va_dhcp_on[0],
- sizeof(buf_reg66va_dhcp_on));
- /* btc_params 41 0x33 */
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg41va_dhcp_on[0],
- sizeof(buf_reg41va_dhcp_on));
- /* btc_params 68 0x190 */
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg68va_dhcp_on[0],
- sizeof(buf_reg68va_dhcp_on));
- saved_status = TRUE;
-
- btco_inf->bt_state = BT_DHCP_START;
- btco_inf->timer_on = 1;
- mod_timer(&btco_inf->timer, btco_inf->timer.expires);
- WL_TRACE(("%s enable BT DHCP Timer\n",
- __FUNCTION__));
- }
-#endif /* COEX_DHCP */
- }
- else if (saved_status == TRUE) {
- WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
- }
- }
- else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
-
-
- /* Restoring PM mode */
-
-#ifdef COEX_DHCP
- /* Stop any bt timer because DHCP session is done */
- WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
- if (btco_inf->timer_on) {
- btco_inf->timer_on = 0;
- del_timer_sync(&btco_inf->timer);
-
- if (btco_inf->bt_state != BT_DHCP_IDLE) {
- /* need to restore original btc flags & extra btc params */
- WL_TRACE(("%s bt->bt_state:%d\n",
- __FUNCTION__, btco_inf->bt_state));
- /* wake up btcoex thread to restore btlags+params */
- schedule_work(&btco_inf->work);
- }
- }
-
- /* Restoring btc_flag paramter anyway */
- if (saved_status == TRUE)
- dev_wlc_bufvar_set(dev, "btc_flags",
- (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
-#endif /* COEX_DHCP */
-
- /* Restore original values */
- if (saved_status == TRUE) {
- regaddr = 66;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg66);
- regaddr = 41;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg41);
- regaddr = 68;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg68);
-
- WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
- saved_reg66, saved_reg41, saved_reg68));
- }
- saved_status = FALSE;
-
- }
- else {
- WL_ERR(("%s Unkwown yet power setting, ignored\n",
- __FUNCTION__));
- }
-
- snprintf(command, 3, "OK");
-
- return (strlen("OK"));
+ wl_dbg_level |= WL_DBG_DBG;
}