Samsung VZW MB1 update
/drivers/net/wireless/bcmdhd/wl_cfg80211.c
blob:015b411d0cea946887974e7a6d48e980940f7b6b -> blob:cb6da84506ec81d19c2e86f7decd3f8dfb8cf54c
--- drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_cfg80211.c 358102 2012-09-21 04:45:06Z $
+ * $Id: wl_cfg80211.c 375020 2012-12-17 06:10:40Z $
*/
#include <typedefs.h>
@@ -58,6 +58,11 @@
#include <wldev_common.h>
#include <wl_cfg80211.h>
#include <wl_cfgp2p.h>
+#include <wl_android.h>
+
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
#ifdef WL11U
#ifndef WL_ENABLE_P2P_IF
@@ -110,7 +115,7 @@ u32 wl_dbg_level = WL_DBG_ERR;
#ifdef VSDB
/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
-#define DEFAULT_SLEEP_TIME_VSDB 200
+#define DEFAULT_SLEEP_TIME_VSDB 200
#define OFF_CHAN_TIME_THRESHOLD_MS 200
/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
@@ -140,6 +145,10 @@ u32 wl_dbg_level = WL_DBG_ERR;
#define DNGL_FUNC(func, parameters) func parameters;
#define COEX_DHCP
+#define WLAN_EID_SSID 0
+#define CH_MIN_5G_CHANNEL 34
+#define CH_MIN_2G_CHANNEL 1
+
/* 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
* and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
@@ -255,6 +264,12 @@ static s32 wl_cfg80211_get_key(struct wi
static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
struct net_device *dev, u8 key_idx);
static s32 wl_cfg80211_resume(struct wiphy *wiphy);
+#if 0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie);
+static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, u8* mac_addr);
+#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
#else
@@ -301,6 +316,15 @@ static s32 wl_bss_roaming_done(struct wl
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 */
static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info,
enum wl_status state, bool set);
/*
@@ -369,10 +393,9 @@ static s32 wl_setup_wiphy(struct wireles
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 s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done);
+static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done);
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,
struct key_params *params);
@@ -480,11 +503,16 @@ do { \
extern int dhd_wait_pend8021x(struct net_device *dev);
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
extern int disable_proptx;
extern int dhd_wlfc_init(dhd_pub_t *dhd);
extern void dhd_wlfc_deinit(dhd_pub_t *dhd);
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
+
+#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE)
+extern int
+dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size);
+#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */
#if (WL_DBG_LEVEL > 0)
#define WL_DBG_ESTR_MAX 50
@@ -958,7 +986,7 @@ static chanspec_t wl_cfg80211_get_shared
else {
bss = (struct wl_bss_info *) (wl->extra_buf + 4);
chspec = bss->chanspec;
- WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec));
+ WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
}
return chspec;
}
@@ -987,26 +1015,24 @@ wl_cfg80211_add_virtual_iface(struct wip
s32 wlif_type = -1;
s32 mode = 0;
s32 val = 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;
struct ether_addr primary_mac;
int (*net_attach)(void *dhdp, int ifidx);
bool rollback_lock = false;
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
s32 up = 1;
dhd_pub_t *dhd;
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
if (!wl)
return ERR_PTR(-EINVAL);
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
dhd = (dhd_pub_t *)(wl->pub);
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
/* Use primary I/F for sending cmds down to firmware */
@@ -1077,11 +1103,11 @@ wl_cfg80211_add_virtual_iface(struct wip
return ERR_PTR(-ENOMEM);
}
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
if (!dhd)
return ERR_PTR(-ENODEV);
-#endif /* PROP_TXSTATUS */
- if (!wl->p2p || !wl->p2p->vir_ifname)
+#endif /* PROP_TXSTATUS_VSDB */
+ if (!wl->p2p)
return ERR_PTR(-ENODEV);
if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
@@ -1097,7 +1123,7 @@ wl_cfg80211_add_virtual_iface(struct wip
strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
wl_notify_escan_complete(wl, _ndev, true, true);
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
if (!wl->wlfc_on && !disable_proptx) {
dhd->wlfc_enabled = true;
dhd_wlfc_init(dhd);
@@ -1106,7 +1132,7 @@ wl_cfg80211_add_virtual_iface(struct wip
WL_ERR(("WLC_UP return err:%d\n", err));
wl->wlfc_on = true;
}
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
/* 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
@@ -1167,13 +1193,11 @@ wl_cfg80211_add_virtual_iface(struct wip
"created net attach done\n", wl->p2p->vir_ifname));
if (mode == WL_MODE_AP)
wl_set_drv_status(wl, CONNECTED, _ndev);
-#if defined(WL_ENABLE_P2P_IF)
if (type == NL80211_IFTYPE_P2P_CLIENT)
- dhd_mode = P2P_GC_ENABLED;
+ dhd_mode = DHD_FLAG_P2P_GC_MODE;
else if (type == NL80211_IFTYPE_P2P_GO)
- dhd_mode = P2P_GO_ENABLED;
+ dhd_mode = DHD_FLAG_P2P_GO_MODE;
DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode));
-#endif /* (WL_ENABLE_P2P_IF) */
} else {
/* put back the rtnl_lock again */
if (rollback_lock)
@@ -1190,13 +1214,13 @@ wl_cfg80211_add_virtual_iface(struct wip
WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname));
memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
wl->p2p->vif_created = false;
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
if (dhd->wlfc_enabled && wl->wlfc_on) {
dhd->wlfc_enabled = false;
dhd_wlfc_deinit(dhd);
wl->wlfc_on = false;
}
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
}
}
fail:
@@ -1242,9 +1266,7 @@ wl_cfg80211_del_virtual_iface(struct wip
(&wl->iface_disable, msecs_to_jiffies(500));
}
wl_set_p2p_status(wl, IF_DELETING);
-#if defined(WL_ENABLE_P2P_IF)
DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl));
-#endif /* (WL_ENABLE_P2P_IF)) */
/* for GO */
if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
@@ -1262,6 +1284,7 @@ wl_cfg80211_del_virtual_iface(struct wip
msleep(300);
}
}
+ wl_cfgp2p_clear_management_ie(wl, wl_cfgp2p_find_idx(wl, dev));
/* delete interface after link down */
ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
/* Firmware could not delete the interface so we will not get WLC_E_IF
@@ -1275,7 +1298,7 @@ wl_cfg80211_del_virtual_iface(struct wip
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);
+ net_os_send_hang_message(ndev);
}
/* Wait for IF_DEL operation to be finished in firmware */
timeout = wait_event_interruptible_timeout(wl->netif_change_event,
@@ -1303,7 +1326,7 @@ wl_cfg80211_change_virtual_iface(struct
s32 mode = 0;
chanspec_t chspec;
struct wl_priv *wl = wiphy_priv(wiphy);
-
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
WL_DBG(("Enter type %d\n", type));
switch (type) {
case NL80211_IFTYPE_MONITOR:
@@ -1330,7 +1353,8 @@ wl_cfg80211_change_virtual_iface(struct
default:
return -EINVAL;
}
-
+ if (!dhd)
+ return -EINVAL;
if (ap) {
wl_set_mode_by_netdev(wl, ndev, mode);
if (wl->p2p_supported && wl->p2p->vif_created) {
@@ -1355,6 +1379,8 @@ wl_cfg80211_change_virtual_iface(struct
(wl_get_p2p_status(wl, IF_CHANGED) == true),
msecs_to_jiffies(MAX_WAIT_TIME));
wl_set_mode_by_netdev(wl, ndev, mode);
+ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
+ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
wl_clr_p2p_status(wl, IF_CHANGING);
wl_clr_p2p_status(wl, IF_CHANGED);
if (mode == WL_MODE_AP)
@@ -1367,6 +1393,9 @@ wl_cfg80211_change_virtual_iface(struct
WL_ERR(("struct ap_saved_ie allocation failed\n"));
return -ENOMEM;
}
+#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE)
+ dhdsdio_func_blocksize(dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY);
+#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */
} else {
WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
return -EINVAL;
@@ -1425,9 +1454,9 @@ wl_cfg80211_ifdel_ops(struct net_device
struct wl_priv *wl = wlcfg_drv_priv;
bool rollback_lock = false;
s32 index = 0;
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
if (!ndev || (strlen(ndev->name) == 0)) {
WL_ERR(("net is NULL\n"));
return 0;
@@ -1454,18 +1483,17 @@ wl_cfg80211_ifdel_ops(struct net_device
memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
index = wl_cfgp2p_find_idx(wl, ndev);
wl_to_p2p_bss_ndev(wl, index) = NULL;
- wl_to_p2p_bss_bssidx(wl, index) = 0;
+ wl_to_p2p_bss_bssidx(wl, index) = WL_INVALID;
wl->p2p->vif_created = false;
- wl_cfgp2p_clear_management_ie(wl,
- index);
+
WL_DBG(("index : %d\n", index));
-#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
if (dhd->wlfc_enabled && wl->wlfc_on) {
dhd->wlfc_enabled = false;
dhd_wlfc_deinit(dhd);
wl->wlfc_on = false;
}
-#endif /* PROP_TXSTATUS */
+#endif /* PROP_TXSTATUS_VSDB */
wl_clr_drv_status(wl, CONNECTED, ndev);
}
/* Wake up any waiting thread */
@@ -1567,7 +1595,7 @@ static void wl_scan_prep(struct wl_scan_
u32 n_channels;
u16 channel;
chanspec_t chanspec;
- s32 i = 0, offset;
+ s32 i = 0, j = 0, offset;
char *ptr;
wlc_ssid_t ssid;
struct wl_priv *wl = wlcfg_drv_priv;
@@ -1613,25 +1641,39 @@ static void wl_scan_prep(struct wl_scan_
(IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)))
continue;
- if (request->channels[i]->band == IEEE80211_BAND_2GHZ)
+ if (request->channels[i]->band == IEEE80211_BAND_2GHZ) {
+#ifdef WL_HOST_BAND_MGMT
+ if (wl->curr_band == WLC_BAND_5G) {
+ WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel));
+ continue;
+ }
+#endif /* WL_HOST_BAND_MGMT */
chanspec |= WL_CHANSPEC_BAND_2G;
- else
+ } else {
+#ifdef WL_HOST_BAND_MGMT
+ if (wl->curr_band == WLC_BAND_2G) {
+ WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel));
+ continue;
+ }
+#endif /* WL_HOST_BAND_MGMT */
chanspec |= WL_CHANSPEC_BAND_5G;
+ }
chanspec |= WL_CHANSPEC_BW_20;
chanspec |= WL_CHANSPEC_CTL_SB_NONE;
- params->channel_list[i] = channel;
- params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK;
- params->channel_list[i] |= chanspec;
+ params->channel_list[j] = channel;
+ params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK;
+ params->channel_list[j] |= chanspec;
WL_SCAN(("Chan : %d, Channel spec: %x \n",
- channel, params->channel_list[i]));
- params->channel_list[i] = wl_chspec_host_to_driver(params->channel_list[i]);
+ channel, params->channel_list[j]));
+ params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]);
+ j++;
}
} else {
WL_SCAN(("Scanning all channels\n"));
}
- n_channels = i;
+ n_channels = j;
/* Copy ssid array if applicable */
WL_SCAN(("### List of SSIDs to scan ###\n"));
if (n_ssids > 0) {
@@ -1673,21 +1715,19 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan
struct wl_iscan_params *params = NULL;
s32 err = 0;
- if (request == NULL) {
- err = -EINVAL;
- goto done;
- }
- n_channels = request->n_channels;
- n_ssids = request->n_ssids;
- /* Allocate space for populating ssids in wl_iscan_params struct */
- if (n_channels % 2)
- /* If n_channels is odd, add a padd of u16 */
- params_size += sizeof(u16) * (n_channels + 1);
- else
- params_size += sizeof(u16) * n_channels;
+ if (request != NULL) {
+ n_channels = request->n_channels;
+ n_ssids = request->n_ssids;
+ /* Allocate space for populating ssids in wl_iscan_params struct */
+ if (n_channels % 2)
+ /* If n_channels is odd, add a padd of u16 */
+ params_size += sizeof(u16) * (n_channels + 1);
+ else
+ params_size += sizeof(u16) * n_channels;
- /* Allocate space for populating ssids in wl_iscan_params struct */
- params_size += sizeof(struct wlc_ssid) * n_ssids;
+ /* Allocate space for populating ssids in wl_iscan_params struct */
+ params_size += sizeof(struct wlc_ssid) * n_ssids;
+ }
params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
if (!params) {
err = -ENOMEM;
@@ -1731,7 +1771,7 @@ static s32 wl_do_iscan(struct wl_priv *w
passive_scan = wl->active_scan ? 0 : 1;
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
- &passive_scan, sizeof(passive_scan), false);
+ &passive_scan, sizeof(passive_scan), true);
if (unlikely(err)) {
WL_DBG(("error (%d)\n", err));
return err;
@@ -1788,9 +1828,10 @@ wl_run_escan(struct wl_priv *wl, struct
#ifdef USE_INITIAL_2G_SCAN
bool is_first_init_2g_scan = false;
#endif /* USE_INITIAL_2G_SCAN */
+
WL_DBG(("Enter \n"));
- if (!request || !wl) {
+ if (!wl) {
err = -EINVAL;
goto exit;
}
@@ -1798,6 +1839,9 @@ wl_run_escan(struct wl_priv *wl, struct
/* LEGACY SCAN TRIGGER */
WL_SCAN((" LEGACY E-SCAN START\n"));
+ /* if scan request is not empty parse scan request paramters */
+ if (request != NULL) {
+
#ifdef USE_INITIAL_2G_SCAN
if (ndev == wl_to_prmry_ndev(wl) && g_first_broadcast_scan == true) {
j = 0;
@@ -1838,6 +1882,7 @@ wl_run_escan(struct wl_priv *wl, struct
/* Allocate space for populating ssids in wl_iscan_params struct */
params_size += sizeof(struct wlc_ssid) * n_ssids;
+ }
params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
if (params == NULL) {
err = -ENOMEM;
@@ -1889,20 +1934,33 @@ wl_run_escan(struct wl_priv *wl, struct
n_valid_chan = dtoh32(list->count);
for (i = 0; i < num_chans; i++)
{
+#ifdef WL_HOST_BAND_MGMT
+ int channel_band = 0;
+#endif /* WL_HOST_BAND_MGMT */
_freq = request->channels[i]->center_freq;
channel = ieee80211_frequency_to_channel(_freq);
- /* remove DFS channels */
- if (!(request->channels[i]->flags &
+#ifdef WL_HOST_BAND_MGMT
+ channel_band = (channel > CH_MAX_2G_CHANNEL) ?
+ WLC_BAND_5G : WLC_BAND_2G;
+ if ((wl->curr_band != WLC_BAND_AUTO) &&
+ (wl->curr_band != channel_band) &&
+ !IS_P2P_SOCIAL_CHANNEL(channel))
+ continue;
+#endif /* WL_HOST_BAND_MGMT */
+
+ /* ignore DFS channels */
+ if (request->channels[i]->flags &
(IEEE80211_CHAN_RADAR
- | IEEE80211_CHAN_PASSIVE_SCAN))) {
- 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;
- }
+ | IEEE80211_CHAN_PASSIVE_SCAN))
+ continue;
+
+ 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;
}
}
@@ -1963,7 +2021,7 @@ wl_do_escan(struct wl_priv *wl, struct w
wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
passive_scan = wl->active_scan ? 0 : 1;
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
- &passive_scan, sizeof(passive_scan), false);
+ &passive_scan, sizeof(passive_scan), true);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
goto exit;
@@ -2036,6 +2094,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy,
}
#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
/* Arm scan timeout timer */
mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS));
iscan_req = false;
@@ -2177,7 +2236,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy,
WL_SCAN(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
passive_scan = wl->active_scan ? 0 : 1;
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
- &passive_scan, sizeof(passive_scan), false);
+ &passive_scan, sizeof(passive_scan), true);
if (unlikely(err)) {
WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
goto scan_out;
@@ -2229,7 +2288,7 @@ scan_out:
if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID,
&bssid, ETHER_ADDR_LEN, false)) == 0)
WL_ERR(("FW is connected with " MACDBG "/n",
- STR_TO_MACD(bssid.octet)));
+ MAC2STRDBG(bssid.octet)));
else
WL_ERR(("GET BSSID failed with %d\n", ret));
@@ -2244,6 +2303,7 @@ scan_out:
spin_lock_irqsave(&wl->cfgdrv_lock, flags);
wl->scan_request = NULL;
spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+
return err;
}
@@ -2296,7 +2356,7 @@ static s32 wl_set_retry(struct net_devic
u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
retry = htod32(retry);
- err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), false);
+ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true);
if (unlikely(err)) {
WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
return err;
@@ -2414,7 +2474,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiph
memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
- sizeof(join_params), false);
+ sizeof(join_params), true);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
@@ -2520,11 +2580,7 @@ wl_set_auth_type(struct net_device *dev,
WL_DBG(("shared key\n"));
break;
case NL80211_AUTHTYPE_AUTOMATIC:
-#ifdef USE_WEP_AUTH_SHARED_OPEN
- val = WL_AUTH_SHARED_OPEN;
-#else
val = WL_AUTH_OPEN_SHARED;
-#endif /* USE_WEP_AUTH_SHARED_OPEN */
WL_DBG(("automatic\n"));
break;
#ifdef BCMCCX
@@ -2839,7 +2895,7 @@ wl_cfg80211_connect(struct wiphy *wiphy,
wl_extjoin_params_t *ext_join_params;
struct wl_join_params join_params;
size_t join_params_size;
-#ifdef ROAM_AP_ENV_DETECTION
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
#endif /* ROAM_AP_ENV_DETECTION */
s32 err = 0;
@@ -2897,7 +2953,7 @@ wl_cfg80211_connect(struct wiphy *wiphy,
scbval.val = htod32(scbval.val);
WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n",
- STR_TO_MACD(bssid.octet)));
+ MAC2STRDBG(bssid.octet)));
err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t), true);
if (unlikely(err)) {
@@ -2950,7 +3006,7 @@ wl_cfg80211_connect(struct wiphy *wiphy,
return err;
}
}
-#ifdef ROAM_AP_ENV_DETECTION
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
if (dhd->roam_env_detection && (wldev_iovar_setint(dev, "roam_env_detection",
AP_ENV_DETECT_NOT_USED) == BCME_OK)) {
s32 roam_trigger[2] = {WL_AUTO_ROAM_TRIGGER, WLC_BAND_ALL};
@@ -3047,12 +3103,13 @@ wl_cfg80211_connect(struct wiphy *wiphy,
}
ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
+ wl_update_prof(wl, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
/* 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 = DHD_SCAN_ACTIVE_TIME*8;
- ext_join_params->scan.passive_time = DHD_SCAN_PASSIVE_TIME*3;
+ ext_join_params->scan.active_time = WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS;
+ ext_join_params->scan.passive_time = WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS;
/* Set up join scan parameters */
ext_join_params->scan.scan_type = -1;
ext_join_params->scan.nprobes
@@ -3635,7 +3692,7 @@ wl_cfg80211_get_station(struct wiphy *wi
}
if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
- STR_TO_MACD(mac), STR_TO_MACD(curmacp)));
+ MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
}
/* Report the current tx rate */
@@ -3686,6 +3743,23 @@ get_station_err:
return err;
}
+/* Function to update sta power save mode for Kernel wifi stack */
+int wl_cfg80211_update_power_mode(struct net_device *dev)
+{
+ int pm = -1;
+ int err;
+
+ err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false);
+ if (err || (pm == -1)) {
+ WL_ERR(("error (%d)\n", err));
+ } else {
+ pm = (pm == PM_OFF) ? false : true;
+ WL_DBG(("%s: %d\n", __func__, pm));
+ if (dev->ieee80211_ptr)
+ dev->ieee80211_ptr->ps = pm;
+ }
+ return err;
+}
static s32
wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, s32 timeout)
@@ -3694,21 +3768,31 @@ wl_cfg80211_set_power_mgmt(struct wiphy
s32 err = 0;
struct wl_priv *wl = wiphy_priv(wiphy);
struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev);
-
+#if !defined(SUPPORT_PM2_ONLY)
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+#endif /* SUPPORT_PM2_ONLY */
CHECK_SYS_UP(wl);
- if (wl->p2p_net == dev || _net_info == NULL) {
+ if (wl->p2p_net == dev || _net_info == NULL || wl->vsdb_mode) {
return err;
}
+ WL_DBG(("%s: Enter power save enabled %d\n", dev->name, enabled));
+#if !defined(SUPPORT_PM2_ONLY)
+ /* android has special hooks to change pm when kernel suspended */
+ pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF;
+#else
pm = enabled ? PM_FAST : PM_OFF;
- /* Do not enable the power save after assoc if it is p2p interface */
- if (_net_info->pm_block || wl->vsdb_mode) {
- WL_DBG(("Do not enable the power save\n"));
+#endif /* SUPPORT_PM2_ONLY */
+
+ if (_net_info->pm_block) {
+ /* Do not enable the power save if it is p2p interface or vsdb mode is set */
+ WL_DBG(("%s:Do not enable the power save for pm_block %d or vsdb_mode %d\n",
+ dev->name, _net_info->pm_block, wl->vsdb_mode));
pm = PM_OFF;
}
pm = htod32(pm);
- WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
+ WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
if (unlikely(err)) {
if (err == -ENODEV)
@@ -3997,6 +4081,13 @@ wl_cfg80211_remain_on_channel(struct wip
} else {
ndev = dev;
}
+
+ if (!wl->p2p) {
+ WL_ERR(("wl->p2p is not initialized\n"));
+ err = BCME_ERROR;
+ goto exit;
+ }
+
#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
if (wl_get_drv_status(wl, SCANNING, ndev)) {
wl_notify_escan_complete(wl, ndev, true, true);
@@ -4334,13 +4425,7 @@ wl_cfg80211_send_action_frame(struct wip
#ifdef VSDB
ulong off_chan_started_jiffies = 0;
#endif
-
-#ifdef WL11U
- if (!af_params || !action_frame || (!p2p_is_on(wl) && !wl->wl11u))
-#else
- if (!af_params || !action_frame || !p2p_is_on(wl))
- return false;
-#endif
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len);
@@ -4384,7 +4469,7 @@ wl_cfg80211_send_action_frame(struct wip
} else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
/* service discovery process */
if (action == P2PSD_ACTION_ID_GAS_IREQ ||
- action == P2PSD_ACTION_ID_GAS_IREQ) {
+ action == P2PSD_ACTION_ID_GAS_CREQ) {
/* configure service discovery query frame */
config_af_params.search_channel = true;
@@ -4394,7 +4479,7 @@ wl_cfg80211_send_action_frame(struct wip
af_params->dwell_time = WL_MED_DWELL_TIME;
} else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
- action == P2PSD_ACTION_ID_GAS_IRESP) {
+ action == P2PSD_ACTION_ID_GAS_CRESP) {
/* configure service discovery response frame */
af_params->dwell_time = WL_MIN_DWELL_TIME;
} else {
@@ -4408,7 +4493,11 @@ wl_cfg80211_send_action_frame(struct wip
/* do not configure anything. it will be sent with a default configuration */
} else {
WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
- category, action));
+ category, action));
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev);
+ return false;
+ }
}
/* To make sure to send successfully action frame, we have to turn off mpc */
@@ -4636,8 +4725,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy,
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,
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
sizeof(scb_val_t), true);
+ if (err < 0)
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
scb_val.val));
@@ -5509,6 +5600,53 @@ static s32 wl_cfg80211_hostapd_sec(
return 0;
}
+#if 0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+static s32
+wl_cfg80211_del_station(
+ struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8* mac_addr)
+{
+ struct net_device *dev;
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ scb_val_t scb_val;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+
+ WL_DBG(("Entry\n"));
+ if (mac_addr == NULL) {
+ WL_DBG(("mac_addr is NULL ignore it\n"));
+ return 0;
+ }
+
+ if (ndev == wl->p2p_net) {
+ dev = wl_to_prmry_ndev(wl);
+ } else {
+ dev = ndev;
+ }
+
+ if (p2p_is_on(wl)) {
+ /* Suspend P2P discovery search-listen to prevent it from changing the
+ * channel.
+ */
+ if ((wl_cfgp2p_discover_enable_search(wl, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ return -EFAULT;
+ }
+ }
+
+ memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
+ scb_val.val = DOT11_RC_DEAUTH_LEAVING;
+ if (wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true))
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON failed\n"));
+ WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf),
+ scb_val.val));
+ wl_delay(400);
+ return 0;
+}
+#endif
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
static s32
wl_cfg80211_start_ap(
@@ -5638,49 +5776,6 @@ wl_cfg80211_stop_ap(
exit:
return err;
}
-static s32
-wl_cfg80211_del_station(
- struct wiphy *wiphy,
- struct net_device *ndev,
- u8* mac_addr)
-{
- struct net_device *dev;
- struct wl_priv *wl = wiphy_priv(wiphy);
- scb_val_t scb_val;
- s8 eabuf[ETHER_ADDR_STR_LEN];
-
- WL_DBG(("Entry\n"));
- if (mac_addr == NULL) {
- WL_DBG(("mac_addr is NULL ignore it\n"));
- return 0;
- }
-
- if (ndev == wl->p2p_net) {
- dev = wl_to_prmry_ndev(wl);
- } else {
- dev = ndev;
- }
-
- if (p2p_is_on(wl)) {
- /* Suspend P2P discovery search-listen to prevent it from changing the
- * channel.
- */
- if ((wl_cfgp2p_discover_enable_search(wl, false)) < 0) {
- WL_ERR(("Can not disable discovery mode\n"));
- return -EFAULT;
- }
- }
-
- memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
- scb_val.val = DOT11_RC_DEAUTH_LEAVING;
- 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 *)mac_addr, eabuf),
- scb_val.val));
- wl_delay(400);
- return 0;
-}
static s32
wl_cfg80211_change_beacon(
@@ -5850,6 +5945,105 @@ fail:
}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME 30
+#define PNO_REPEAT 4
+#define PNO_FREQ_EXPO_MAX 2
+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"));
+ WL_PNO((">>> SCHED SCAN START\n"));
+ WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
+ request->n_match_sets, request->n_ssids));
+ WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+
+ 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_PNO((">>> 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_PNO((">>> 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"));
+ WL_PNO((">>> SCHED SCAN STOP\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_PNO((">>> Sched scan running. Aborting it..\n"));
+ 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,
@@ -5887,8 +6081,17 @@ static struct cfg80211_ops wl_cfg80211_o
.change_beacon = wl_cfg80211_change_beacon,
.start_ap = wl_cfg80211_start_ap,
.stop_ap = wl_cfg80211_stop_ap,
- .del_station = wl_cfg80211_del_station,
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */
+#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) */
+#if 0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+#ifndef CUSTOMER_HW4
+ .del_station = wl_cfg80211_del_station,
+#endif /* CUSTOMER_HW4 */
+ .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
+#endif
};
s32 wl_mode_to_nl80211_iftype(s32 mode)
@@ -5924,6 +6127,12 @@ static s32 wl_setup_wiphy(struct wireles
/* 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)
#if !(defined(WLP2P) && defined(WL_ENABLE_P2P_IF))
@@ -5965,7 +6174,7 @@ static s32 wl_setup_wiphy(struct wireles
wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_OFFCHAN_TX;
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+#if 0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
/* From 3.4 kernel ownards AP_SME flag can be advertised
* to remove the patch from supplicant
*/
@@ -6020,7 +6229,7 @@ static s32 wl_inform_bss(struct wl_priv
#ifdef ROAM_CHANNEL_CACHE
add_roam_cache(bi);
#endif
- err = wl_inform_single_bss(wl, bi);
+ err = wl_inform_single_bss(wl, bi, 0);
if (unlikely(err))
break;
}
@@ -6030,7 +6239,7 @@ static s32 wl_inform_bss(struct wl_priv
return err;
}
-static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
+static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done)
{
struct wiphy *wiphy = wl_to_wiphy(wl);
struct ieee80211_mgmt *mgmt;
@@ -6045,6 +6254,7 @@ static s32 wl_inform_single_bss(struct w
u32 freq;
s32 err = 0;
gfp_t aflags;
+ u8 *ie_offset = NULL;
if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
WL_DBG(("Beacon is larger than buffer. Discarding\n"));
@@ -6085,7 +6295,36 @@ static s32 wl_inform_single_bss(struct w
beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
wl_rst_ie(wl);
- wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
+ ie_offset = ((u8 *) bi) + bi->ie_offset;
+
+ if (is_roam_done && ((int)(*(ie_offset)) == WLAN_EID_SSID &&
+ ((int)(*(ie_offset+1)) == 0 || (int)(*(ie_offset+2)) == 0))) {
+ u8 *ie_new_offset = NULL;
+ uint8 ie_new_length;
+
+ WL_ERR(("WAR trace: Changing the SSID Info, from beacon %d\n",
+ bi->flags & WL_BSS_FLAGS_FROM_BEACON));
+
+ ie_new_offset = (u8 *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (ie_new_offset) {
+ *(ie_new_offset) = WLAN_EID_SSID;
+ *(ie_new_offset+1) = bi->SSID_len;
+ memcpy(ie_new_offset+2, bi->SSID, bi->SSID_len);
+ ie_new_length = bi->ie_length - *(ie_offset+1) + bi->SSID_len;
+
+ /* Copy the remaining IE apart from SSID IE from bi */
+ memcpy(ie_new_offset+2 + bi->SSID_len,
+ ie_offset+2 + *(ie_offset+1),
+ bi->ie_length - 2 - *(ie_offset+1));
+ wl_mrg_ie(wl, ie_new_offset, ie_new_length);
+ kfree(ie_new_offset);
+ } else {
+ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
+ }
+ } else {
+ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
+ }
+
wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX -
offsetof(struct wl_cfg80211_bss_info, frame_buf));
notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
@@ -6233,16 +6472,17 @@ wl_notify_connect_status_ap(struct wl_pr
struct station_info sinfo;
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */
+ WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason));
/* if link down, bsscfg is disabled. */
if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
wl_get_p2p_status(wl, IF_DELETING) && (ndev != wl_to_prmry_ndev(wl))) {
+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
WL_INFO(("AP mode link down !! \n"));
complete(&wl->iface_disable);
return 0;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
- body = kzalloc(len, GFP_KERNEL);
WL_DBG(("Enter \n"));
if (!len && (event == WLC_E_DEAUTH)) {
len = 2; /* reason code field */
@@ -6355,6 +6595,9 @@ exit:
}
sinfo.assoc_req_ies = data;
sinfo.assoc_req_ies_len = len;
+#ifdef BCM4330_CHIP
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+#endif
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);
@@ -6414,7 +6657,7 @@ wl_notify_connect_status(struct wl_priv
} else {
if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
printk("wl_bss_connect_done succeeded with " MACDBG "\n",
- STR_TO_MACD((u8*)(&e->addr)));
+ MAC2STRDBG((u8*)(&e->addr)));
wl_bss_connect_done(wl, ndev, e, data, true);
WL_DBG(("joined in BSS network \"%s\"\n",
((struct wlc_ssid *)
@@ -6445,11 +6688,11 @@ wl_notify_connect_status(struct wl_priv
printk("link down if %s may call cfg80211_disconnected. "
"event : %d, reason=%d from " MACDBG "\n",
ndev->name, event, ntoh32(e->reason),
- STR_TO_MACD((u8*)(&e->addr)));
+ MAC2STRDBG((u8*)(&e->addr)));
if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
WL_ERR(("BSSID of event is not the connected BSSID"
"(ignore it) cur: " MACDBG " event: " MACDBG"\n",
- STR_TO_MACD(curbssid), STR_TO_MACD((u8*)(&e->addr))));
+ MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr))));
return 0;
}
wl_clr_drv_status(wl, CONNECTED, ndev);
@@ -6645,7 +6888,7 @@ static void wl_ch_to_chanspec(int ch, st
}
}
-static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
+static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done)
{
struct cfg80211_bss *bss;
struct wl_bss_info *bi;
@@ -6655,6 +6898,7 @@ static s32 wl_update_bss_info(struct wl_
s32 dtim_period;
size_t ie_len;
u8 *ie;
+ u8 *ssidie;
u8 *curbssid;
s32 err = 0;
struct wiphy *wiphy;
@@ -6685,7 +6929,14 @@ static s32 wl_update_bss_info(struct wl_
err = -EIO;
goto update_bss_info_out;
}
- err = wl_inform_single_bss(wl, bi);
+
+ ie = ((u8 *)bi) + bi->ie_offset;
+ ie_len = bi->ie_length;
+ ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len);
+ if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0])
+ memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
+
+ err = wl_inform_single_bss(wl, bi, is_roam_done);
if (unlikely(err))
goto update_bss_info_out;
@@ -6736,10 +6987,10 @@ wl_bss_roaming_done(struct wl_priv *wl,
wl_get_assoc_ies(wl, ndev);
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_bss_info(wl, ndev, 1);
wl_update_pmklist(ndev, wl->pmk_list, err);
printk("wl_bss_roaming_done succeeded to " MACDBG "\n",
- STR_TO_MACD((u8*)(&e->addr)));
+ MAC2STRDBG((u8*)(&e->addr)));
cfg80211_roamed(ndev,
@@ -6764,19 +7015,20 @@ wl_bss_connect_done(struct wl_priv *wl,
{
struct wl_connect_info *conn_info = wl_to_conn(wl);
struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC);
-#ifdef ROAM_AP_ENV_DETECTION
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
#endif /* ROAM_AP_ENV_DETECTION */
s32 err = 0;
u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
if (!sec) {
WL_ERR(("sec is NULL\n"));
+ return -ENODEV;
}
WL_DBG((" enter\n"));
#ifdef ESCAN_RESULT_PATCH
if (wl_get_drv_status(wl, CONNECTED, ndev)) {
if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
- WL_ERR((" Connected event of connected device e=%d s=%d, ignore it\n",
+ WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n",
ntoh32(e->event_type), ntoh32(e->status)));
return err;
}
@@ -6803,10 +7055,10 @@ wl_bss_connect_done(struct wl_priv *wl,
wl_get_assoc_ies(wl, ndev);
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_bss_info(wl, ndev, 0);
wl_update_pmklist(ndev, wl->pmk_list, err);
wl_set_drv_status(wl, CONNECTED, ndev);
-#ifdef ROAM_AP_ENV_DETECTION
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
if (dhd->roam_env_detection)
wldev_iovar_setint(ndev, "roam_env_detection",
AP_ENV_INDETERMINATE);
@@ -6851,6 +7103,30 @@ wl_notify_mic_status(struct wl_priv *wl,
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"));
+
+#ifndef WL_SCHED_SCAN
+#ifndef CUSTOMER_HW4
+ mutex_lock(&wl->usr_sync);
+ /* TODO: Use cfg80211_sched_scan_results(wiphy); */
+ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+ mutex_unlock(&wl->usr_sync);
+#endif /* !CUSTOMER_HW4 */
+#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 */
+ 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)
@@ -7122,7 +7398,9 @@ wl_notify_rx_mgmt_frame(struct wl_priv *
wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr",
NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync);
- wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_BSSID error %d\n", err));
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,
@@ -7144,6 +7422,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *
(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]);
if (sd_act_frm && wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) {
@@ -7275,6 +7554,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_PNO(("PFN NET LOST event. Do Nothing \n"));
+ return 0;
+ }
+ WL_PNO((">>> 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_PNO((">>> 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)) {
+ WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
+ 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
+ WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
+ err = wl_do_escan(wl, wiphy, ndev, NULL);
+#else
+ WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
+ 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)
{
WL_DBG(("Enter \n"));
@@ -7317,7 +7712,9 @@ static void wl_init_event_handler(struct
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)
@@ -7785,13 +8182,13 @@ static s32 wl_notify_escan_complete(stru
ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
dev = ndev;
}
- if (fw_abort) {
+ 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 if (!in_atomic()) {
+ } 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) {
@@ -7818,6 +8215,17 @@ static s32 wl_notify_escan_complete(stru
}
#endif /* ESCAN_RESULT_PATCH */
spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+#ifdef WL_SCHED_SCAN
+ if (wl->sched_scan_req && !wl->scan_request) {
+ WL_PNO((">>> 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;
@@ -7860,7 +8268,8 @@ static s32 wl_escan_handler(struct wl_pr
}
if (!ndev || !wl->escan_on ||
- !wl_get_drv_status(wl, SCANNING, ndev)) {
+ (!wl_get_drv_status(wl, SCANNING, ndev) &&
+ !wl->sched_scan_running)) {
#if defined(DUAL_ESCAN_RESULT_BUFFER)
WL_ERR(("escan is not ready ndev %p wl->escan_on %d"
" drv_status 0x%x e_type %d e_states %d\n",
@@ -7919,7 +8328,7 @@ static s32 wl_escan_handler(struct wl_pr
s32 channel = CHSPEC_CHANNEL(
wl_chspec_driver_to_host(bi->chanspec));
WL_DBG(("ACTION FRAME SCAN : Peer " MACDBG " found, channel : %d\n",
- STR_TO_MACD(wl->afx_hdl->tx_dst_addr.octet), channel));
+ MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), channel));
wl_clr_p2p_status(wl, SCANNING);
wl->afx_hdl->peer_chan = channel;
complete(&wl->act_frm_scan);
@@ -7940,6 +8349,10 @@ static s32 wl_escan_handler(struct wl_pr
#else
if (p2p_is_on(wl) && p2p_scan(wl)) {
#endif
+#ifdef WL_HOST_BAND_MGMT
+ s32 channel = 0;
+ s32 channel_band = 0;
+#endif /* WL_HOST_BAND_MGMT */
/* p2p scan && allow only probe response */
if (bi->flags & WL_BSS_FLAGS_FROM_BEACON)
goto exit;
@@ -7949,6 +8362,20 @@ static s32 wl_escan_handler(struct wl_pr
" response/beacon\n"));
goto exit;
}
+#ifdef WL_HOST_BAND_MGMT
+ channel = CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec));
+ channel_band = (channel > CH_MAX_2G_CHANNEL) ?
+ WLC_BAND_5G : WLC_BAND_2G;
+
+
+ if ((wl->curr_band == WLC_BAND_5G) &&
+ (channel_band == WLC_BAND_2G)) {
+ /* Avoid sending the GO results in band conflict */
+ if (wl_cfgp2p_retreive_p2pattrib(p2p_ie,
+ P2P_SEID_GROUP_ID) != NULL)
+ goto exit;
+ }
+#endif /* WL_HOST_BAND_MGMT */
}
for (i = 0; i < list->count; i++) {
bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
@@ -7969,7 +8396,7 @@ static s32 wl_escan_handler(struct wl_pr
WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d"
" flags 0x%x, new: RSSI %d flags 0x%x\n",
- bss->SSID, STR_TO_MACD(bi->BSSID.octet), i,
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), i,
bss->RSSI, bss->flags, bi->RSSI, bi->flags));
if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
@@ -7979,7 +8406,7 @@ static s32 wl_escan_handler(struct wl_pr
*/
WL_SCAN(("%s("MACDBG"), same onchan"
", RSSI: prev %d new %d\n",
- bss->SSID, STR_TO_MACD(bi->BSSID.octet),
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
bss->RSSI, bi->RSSI));
bi->RSSI = MAX(bss->RSSI, bi->RSSI);
} else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
@@ -7989,7 +8416,7 @@ static s32 wl_escan_handler(struct wl_pr
*/
WL_SCAN(("%s("MACDBG"), prev onchan"
", RSSI: prev %d new %d\n",
- bss->SSID, STR_TO_MACD(bi->BSSID.octet),
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
bss->RSSI, bi->RSSI));
bi->RSSI = bss->RSSI;
bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
@@ -8001,7 +8428,7 @@ static s32 wl_escan_handler(struct wl_pr
" is occured(bcast:%d->probresp%d)\n",
bss->ie_length, bi->ie_length));
WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n",
- bss->SSID, STR_TO_MACD(bi->BSSID.octet),
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
prev_len, bi_length));
if (list->buflen - prev_len + bi_length
@@ -8060,7 +8487,7 @@ static s32 wl_escan_handler(struct wl_pr
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)) {
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
WL_INFO(("ESCAN COMPLETED\n"));
#if defined(DUAL_ESCAN_RESULT_BUFFER)
wl->bss_list = (wl_scan_results_t *)
@@ -8089,7 +8516,7 @@ static s32 wl_escan_handler(struct wl_pr
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)) {
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
WL_INFO(("ESCAN ABORTED\n"));
#if defined(DUAL_ESCAN_RESULT_BUFFER)
wl->bss_list = (wl_scan_results_t *)
@@ -8125,7 +8552,7 @@ static s32 wl_escan_handler(struct wl_pr
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)) {
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
#if defined(DUAL_ESCAN_RESULT_BUFFER)
wl->bss_list = (wl_scan_results_t *)
wl->escan_info.escan_buf[(wl->escan_info.cur_sync_id+1)%2];
@@ -8143,147 +8570,164 @@ exit:
mutex_unlock(&wl->usr_sync);
return err;
}
+static void wl_cfg80211_concurrent_roam(struct wl_priv *wl, int enable)
+{
+ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED);
+ struct net_info *iter, *next;
+ int err;
+
+ if (!wl->roamoff_on_concurrent)
+ return;
+ if (enable && connected_cnt > 1) {
+ for_each_ndev(wl, iter, next) {
+ /* Save the current roam setting */
+ if ((err = wldev_iovar_getint(iter->ndev, "roam_off",
+ (s32 *)&iter->roam_off)) != BCME_OK) {
+ WL_ERR(("%s:Failed to get current roam setting err %d\n",
+ iter->ndev->name, err));
+ continue;
+ }
+ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) {
+ WL_ERR((" %s:failed to set roam_off : %d\n",
+ iter->ndev->name, err));
+ }
+ }
+ }
+ else if (!enable) {
+ for_each_ndev(wl, iter, next) {
+ if (iter->roam_off != WL_INVALID) {
+ if ((err = wldev_iovar_setint(iter->ndev, "roam_off",
+ iter->roam_off)) == BCME_OK)
+ iter->roam_off = WL_INVALID;
+ else {
+ WL_ERR((" %s:failed to set roam_off : %d\n",
+ iter->ndev->name, err));
+ }
+ }
+ }
+ }
+ return;
+}
+
+static void wl_cfg80211_determine_vsdb_mode(struct wl_priv *wl)
+{
+#ifdef CUSTOMER_HW4
+ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED);
+ if (connected_cnt > 1) {
+ wl->vsdb_mode = true;
+ } else {
+ wl->vsdb_mode = false;
+ }
+ return;
+#else
+ struct net_info *iter, *next;
+ u32 chan = 0;
+ u32 chanspec = 0;
+ u32 prev_chan = 0;
+ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED);
+ wl->vsdb_mode = false;
+
+ if (connected_cnt <= 1) {
+ return;
+ }
+ for_each_ndev(wl, iter, next) {
+ chanspec = 0;
+ chan = 0;
+ if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) {
+ if (wldev_iovar_getint(iter->ndev, "chanspec",
+ (s32 *)&chanspec) == BCME_OK) {
+ chan = CHSPEC_CHANNEL(chanspec);
+ if (CHSPEC_IS40(chanspec)) {
+ if (CHSPEC_SB_UPPER(chanspec))
+ chan += CH_10MHZ_APART;
+ else
+ chan -= CH_10MHZ_APART;
+ }
+ wl_update_prof(wl, iter->ndev, NULL,
+ &chan, WL_PROF_CHAN);
+ }
+ if (!prev_chan && chan)
+ prev_chan = chan;
+ else if (prev_chan && (prev_chan != chan))
+ wl->vsdb_mode = true;
+ }
+ }
+ return;
+#endif /* CUSTOMER_HW4 */
+}
static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info,
enum wl_status state, bool set)
{
s32 pm = PM_FAST;
s32 err = BCME_OK;
u32 chan = 0;
- u32 chanspec = 0;
- u32 prev_chan = 0;
- u32 connected_cnt = 0;
struct net_info *iter, *next;
struct net_device *primary_dev = wl_to_prmry_ndev(wl);
- if (set) { /* set */
- switch (state) {
- case WL_STATUS_CONNECTED: {
- if ((connected_cnt = wl_get_drv_status_all(wl, CONNECTED)) > 1) {
- pm = PM_OFF;
- WL_INFO(("Do not enable the power save for VSDB mode\n"));
- } else if (_net_info->pm_block) {
- pm = PM_OFF;
- } else {
- pm = PM_FAST;
- }
+ WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
+ state, set, _net_info->pm_restore, _net_info->ndev->name));
+
+ if (state != WL_STATUS_CONNECTED)
+ return 0;
+
+ if (set) {
+ wl_cfg80211_concurrent_roam(wl, 1);
+
+ if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) {
+
+ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
+ WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+ wl_cfg80211_determine_vsdb_mode(wl);
+ if (wl->vsdb_mode || _net_info->pm_block) {
+ pm = PM_OFF;
for_each_ndev(wl, iter, next) {
- if ((connected_cnt == 1) && (iter->ndev != _net_info->ndev))
+ if (iter->pm_restore)
continue;
- chanspec = 0;
- chan = 0;
- if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) {
- if (wldev_iovar_getint(iter->ndev, "chanspec",
- (s32 *)&chanspec) == BCME_OK) {
- chan = CHSPEC_CHANNEL(chanspec);
- if (CHSPEC_IS40(chanspec)) {
- if (CHSPEC_SB_UPPER(chanspec))
- chan += CH_10MHZ_APART;
- else
- chan -= CH_10MHZ_APART;
- }
- wl_update_prof(wl, iter->ndev, NULL,
- &chan, WL_PROF_CHAN);
- }
- if ((wl_get_mode_by_netdev(wl, iter->ndev)
- == WL_MODE_BSS)) {
- pm = htod32(pm);
- WL_DBG(("power save %s\n",
- (pm ? "enabled" : "disabled")));
- err = wldev_ioctl(iter->ndev, WLC_SET_PM,
- &pm, sizeof(pm), true);
- if (unlikely(err)) {
- if (err == -ENODEV)
- WL_DBG(("net_device"
- " is not ready\n"));
- else
- WL_ERR(("error"
- " (%d)\n", err));
- break;
- }
- }
- if (connected_cnt > 1) {
- if (!prev_chan && chan)
- prev_chan = chan;
- else if (prev_chan && (prev_chan != chan)) {
- wl->vsdb_mode = true;
- }
- if (wl->roamoff_on_concurrent) {
- if ((err = wldev_iovar_getint(iter->ndev,
- "roam_off", (s32 *)&iter->roam_off))
- == BCME_OK) {
- if ((err =
- wldev_iovar_setint(iter->ndev,
- "roam_off", 1)) !=
- BCME_OK) {
- WL_ERR((" failed to set "
- "roam_off : %d\n", err));
- }
- } else
- WL_ERR(("failed to get"
- " roam_off : %d\n", err));
- }
- }
+ /* Save the current power mode */
+ err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
+ sizeof(iter->pm), false);
+ WL_DBG(("%s:power save %s\n", iter->ndev->name,
+ iter->pm ? "enabled" : "disabled"));
+ if (!err && iter->pm) {
+ iter->pm_restore = true;
}
+
}
- if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) {
- if (wl_add_remove_eventmsg(primary_dev,
- WLC_E_P2P_PROBREQ_MSG, false))
- WL_ERR((" failed to unset"
- " WLC_E_P2P_PROPREQ_MSG\n"));
- }
- break;
- }
- default:
- break;
- }
- } else { /* clear */
- switch (state) {
- case WL_STATUS_CONNECTED: {
- chan = 0;
- /* clear chan information when the net device is disconnected */
- wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
- if (wl_get_drv_status_all(wl, CONNECTED) == 1) {
- wl->vsdb_mode = false;
- for_each_ndev(wl, iter, next) {
- if (wl_get_drv_status(wl, CONNECTED, iter->ndev) &&
- (wl_get_mode_by_netdev(wl, iter->ndev)
- == WL_MODE_BSS)) {
- if (wl_get_netinfo_by_netdev(wl,
- iter->ndev)->pm_block)
- pm = PM_OFF;
- else
- pm = PM_FAST;
- pm = htod32(pm);
- WL_DBG(("power save %s\n",
- (pm ? "enabled" : "disabled")));
- err = wldev_ioctl(iter->ndev,
- WLC_SET_PM, &pm, sizeof(pm), true);
- if (unlikely(err)) {
- if (err == -ENODEV)
- WL_DBG(("net_device"
- " is not ready\n"));
- else
- WL_ERR(("error"
- " (%d)\n", err));
- break;
- }
- }
+ for_each_ndev(wl, iter, next) {
+ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
+ sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+ iter->ndev->ieee80211_ptr->ps = false;
}
}
- if (wl->roamoff_on_concurrent) {
- for_each_ndev(wl, iter, next) {
- if ((iter->roam_off != WL_INVALID) &&
- ((err = wldev_iovar_setint(iter->ndev, "roam_off",
- iter->roam_off)) == BCME_OK)) {
- iter->roam_off = WL_INVALID;
- } else if (err)
- WL_ERR((" failed to set roam_off : %d\n", err));
+ }
+ }
+ else { /* clear */
+ chan = 0;
+ /* clear chan information when the net device is disconnected */
+ wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
+ wl_cfg80211_determine_vsdb_mode(wl);
+ for_each_ndev(wl, iter, next) {
+ if (iter->pm_restore && iter->pm) {
+ WL_DBG(("%s:restoring power save %s\n",
+ iter->ndev->name, (iter->pm ? "enabled" : "disabled")));
+ err = wldev_ioctl(iter->ndev,
+ WLC_SET_PM, &iter->pm, sizeof(iter->pm), true);
+ if (unlikely(err)) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+ else
+ WL_ERR(("%s:error(%d)\n", iter->ndev->name, err));
+ break;
}
+ iter->pm_restore = 0;
+ iter->ndev->ieee80211_ptr->ps = true;
}
- break;
- }
- default:
- break;
}
+ wl_cfg80211_concurrent_roam(wl, 0);
}
return err;
}
@@ -8425,7 +8869,11 @@ s32 wl_cfg80211_attach_post(struct net_d
return -ENODEV;
}
wl = wlcfg_drv_priv;
- if (wl && !wl_get_drv_status(wl, READY, ndev)) {
+ if (unlikely(!wl)) {
+ WL_ERR(("wl is invaild\n"));
+ return -EINVAL;
+ }
+ if (!wl_get_drv_status(wl, READY, ndev)) {
if (wl->wdev &&
wl_cfgp2p_supported(wl, ndev)) {
#if !defined(WL_ENABLE_P2P_IF)
@@ -8443,7 +8891,7 @@ s32 wl_cfg80211_attach_post(struct net_d
wl->p2p_net->dev_addr[0] |= 0x02;
WL_ERR(("%s: p2p_dev_addr="MACDBG "\n",
wl->p2p_net->name,
- STR_TO_MACD(wl->p2p_net->dev_addr)));
+ MAC2STRDBG(wl->p2p_net->dev_addr)));
} else {
WL_ERR(("p2p_net not yet populated."
" Couldn't update the MAC Address for p2p0 \n"));
@@ -8453,8 +8901,7 @@ s32 wl_cfg80211_attach_post(struct net_d
wl->p2p_supported = true;
}
- } else
- return -ENODEV;
+ }
wl_set_drv_status(wl, READY, ndev);
fail:
return err;
@@ -8551,8 +8998,9 @@ void wl_cfg80211_detach(void *para)
wl_setup_rfkill(wl, FALSE);
if (wl->p2p_supported) {
- WL_ERR(("wl_cfgp2p_down() is not called yet\n"));
- wl_cfgp2p_down(wl);
+ if (timer_pending(&wl->p2p->listen_timer))
+ del_timer_sync(&wl->p2p->listen_timer);
+ wl_cfgp2p_deinit_priv(wl);
}
#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
@@ -8663,10 +9111,6 @@ wl_cfg80211_event(struct net_device *nde
u32 event_type = ntoh32(e->event_type);
struct wl_priv *wl = wlcfg_drv_priv;
-#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK)
- int pno_wakelock_timeout = 10; /* 10 second */
-#endif
-
#if (WL_DBG_LEVEL > 0)
s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
wl_dbg_estr[event_type] : (s8 *) "Unknown";
@@ -8674,9 +9118,6 @@ wl_cfg80211_event(struct net_device *nde
#endif /* (WL_DBG_LEVEL > 0) */
if (event_type == WLC_E_PFN_NET_FOUND) {
-#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK)
- net_os_wake_lock_timeout_for_pno(ndev, pno_wakelock_timeout);
-#endif
WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
}
else if (event_type == WLC_E_PFN_NET_LOST) {
@@ -8815,7 +9256,8 @@ s32 wl_add_remove_eventmsg(struct net_de
s8 eventmask[WL_EVENTING_MASK_LEN];
s32 err = 0;
-
+ if (!ndev)
+ return -ENODEV;
/* Setup event_msgs */
bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
sizeof(iovbuf));
@@ -8891,13 +9333,14 @@ static int wl_construct_reginfo(struct w
else
channel -= CH_10MHZ_APART;
}
- if (CHSPEC_IS2G(c) && channel <= CH_MAX_2G_CHANNEL) {
+ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
+ (channel <= CH_MAX_2G_CHANNEL)) {
band_chan_arr = __wl_2ghz_channels;
array_size = ARRAYSIZE(__wl_2ghz_channels);
n_cnt = &n_2g;
band = IEEE80211_BAND_2GHZ;
ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
- } else if (CHSPEC_IS5G(c) && channel > CH_MAX_2G_CHANNEL) {
+ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
band_chan_arr = __wl_5ghz_a_channels;
array_size = ARRAYSIZE(__wl_5ghz_a_channels);
n_cnt = &n_5g;
@@ -8907,6 +9350,8 @@ static int wl_construct_reginfo(struct w
WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
continue;
}
+ if (!ht40_allowed && CHSPEC_IS40(c))
+ continue;
for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
if (band_chan_arr[j].hw_value == channel) {
update = true;
@@ -8989,6 +9434,8 @@ s32 wl_update_wiphybands(struct wl_priv
bool rollback_lock = false;
s32 bw_cap = 0;
s32 cur_band = -1;
+ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]={NULL,};
+
if (wl == NULL) {
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
@@ -9000,9 +9447,12 @@ s32 wl_update_wiphybands(struct wl_priv
err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
sizeof(bandlist), false);
if (unlikely(err)) {
- WL_ERR(("error real bandlist (%d)\n", err));
+ WL_ERR(("error read bandlist (%d)\n", err));
goto end_bands;
}
+
+ wiphy = wl_to_wiphy(wl);
+
err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band,
sizeof(s32), false);
if (unlikely(err)) {
@@ -9028,37 +9478,42 @@ s32 wl_update_wiphybands(struct wl_priv
goto end_bands;
err = 0;
}
- wiphy = wl_to_wiphy(wl);
+
nband = bandlist[0];
- wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+
for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
index = -1;
if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
- wiphy->bands[IEEE80211_BAND_5GHZ] =
+ bands[IEEE80211_BAND_5GHZ] =
&__wl_band_5ghz_a;
index = IEEE80211_BAND_5GHZ;
if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)
- wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
}
else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
- wiphy->bands[IEEE80211_BAND_2GHZ] =
+ bands[IEEE80211_BAND_2GHZ] =
&__wl_band_2ghz;
index = IEEE80211_BAND_2GHZ;
if (bw_cap == WLC_N_BW_40ALL)
- wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
}
if ((index >= 0) && nmode) {
- wiphy->bands[index]->ht_cap.cap |=
+ bands[index]->ht_cap.cap |=
(IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
- 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;
+ bands[index]->ht_cap.ht_supported = TRUE;
+ bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+ /* An HT shall support all EQM rates for one spatial stream */
+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
}
}
+ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
+ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
+
+
wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
end_bands:
if (rollback_lock)
@@ -9089,6 +9544,15 @@ static s32 __wl_cfg80211_up(struct wl_pr
err = dhd_monitor_init(wl->pub);
err = wl_invoke_iscan(wl);
+
+#ifdef WL_HOST_BAND_MGMT
+ /* By default the curr_band is initialized to BAND_AUTO */
+ if (wl_cfg80211_set_band(ndev, WLC_BAND_AUTO) < 0) {
+ WL_ERR(("roam_band set failed\n"));
+ err = -1;
+ }
+#endif /* WL_HOST_BAND_MGMT */
+
wl_set_drv_status(wl, READY, ndev);
return err;
}
@@ -9099,18 +9563,16 @@ static s32 __wl_cfg80211_down(struct wl_
unsigned long flags;
struct net_info *iter, *next;
struct net_device *ndev = wl_to_prmry_ndev(wl);
-#ifdef WL_ENABLE_P2P_IF
-#if !defined(CUSTOMER_HW4)
struct net_device *p2p_net = wl->p2p_net;
-#endif /* !defined(CUSTOMER_HW4) */
-#endif /* WL_ENABLE_P2P_IF */
WL_DBG(("In\n"));
/* Check if cfg80211 interface is already down */
if (!wl_get_drv_status(wl, READY, ndev))
return err; /* it is even not ready */
+
for_each_ndev(wl, iter, next)
wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
+
wl_term_iscan(wl);
spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
@@ -9131,14 +9593,12 @@ static s32 __wl_cfg80211_down(struct wl_
}
wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
NL80211_IFTYPE_STATION;
-#ifdef WL_ENABLE_P2P_IF
-#if !defined(CUSTOMER_HW4)
- if ((p2p_net) && (p2p_net->flags & IFF_UP)) {
- /* p2p0 interface is still UP. Bring it down */
- p2p_net->flags &= ~IFF_UP;
+#if defined(WL_CFG80211) && defined(SUPPORT_DEEP_SLEEP)
+ if (!sleep_never) {
+ if (p2p_net)
+ dev_close(p2p_net);
}
#endif
-#endif /* WL_ENABLE_P2P_IF */
DNGL_FUNC(dhd_cfg80211_down, (wl));
wl_flush_eq(wl);
wl_link_down(wl);
@@ -9155,7 +9615,6 @@ s32 wl_cfg80211_up(void *para)
s32 err = 0;
int val = 1;
dhd_pub_t *dhd;
-
(void)para;
WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
@@ -9176,14 +9635,15 @@ s32 wl_cfg80211_up(void *para)
mutex_lock(&wl->usr_sync);
dhd = (dhd_pub_t *)(wl->pub);
- if ((dhd->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) {
- wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
+ err = wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
+ if (unlikely(err))
+ return err;
}
err = __wl_cfg80211_up(wl);
- if (err)
+ if (unlikely(err))
WL_ERR(("__wl_cfg80211_up failed\n"));
mutex_unlock(&wl->usr_sync);
-
return err;
}
@@ -9237,6 +9697,7 @@ static void *wl_read_prof(struct wl_priv
break;
case WL_PROF_SSID:
rptr = &profile->ssid;
+ break;
case WL_PROF_CHAN:
rptr = &profile->channel;
break;
@@ -9287,6 +9748,7 @@ wl_update_prof(struct wl_priv *wl, struc
break;
case WL_PROF_CHAN:
profile->channel = *(u32*)data;
+ break;
default:
err = -EOPNOTSUPP;
break;
@@ -9624,6 +10086,20 @@ void wl_cfg80211_enable_trace(bool set,
else
wl_dbg_level |= (WL_DBG_LEVEL & level);
}
+#if 0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+static s32
+wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie)
+{
+ /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
+ * is passed with CMD_FRAME. This callback is supposed to cancel
+ * the OFFCHANNEL Wait. Since we are already taking care of that
+ * with the tx_mgmt logic, do nothing here.
+ */
+
+ return 0;
+}
+#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
#ifdef WL11U
bcm_tlv_t *
@@ -9717,3 +10193,29 @@ wl_cfg80211_add_iw_ie(struct wl_priv *wl
return err;
}
#endif /* WL11U */
+
+#ifdef WL_HOST_BAND_MGMT
+s32
+wl_cfg80211_set_band(struct net_device *ndev, int band)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+ int ret = 0;
+ char ioctl_buf[50];
+
+ if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
+ WL_ERR(("Invalid band\n"));
+ return -EINVAL;
+ }
+
+ if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
+ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
+ WL_ERR(("seting roam_band failed code=%d\n", ret));
+ return ret;
+ }
+
+ WL_DBG(("Setting band to %d\n", band));
+ wl->curr_band = band;
+
+ return 0;
+}
+#endif /* WL_HOST_BAND_MGMT */