aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/wl_roam.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_roam.c')
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wl_roam.c241
1 files changed, 135 insertions, 106 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_roam.c b/drivers/net/wireless/bcmdhd/wl_roam.c
index 25f93ab..6238c15 100755
--- a/drivers/net/wireless/bcmdhd/wl_roam.c
+++ b/drivers/net/wireless/bcmdhd/wl_roam.c
@@ -1,7 +1,7 @@
/*
* Linux roam cache
*
- * Copyright (C) 1999-2012, Broadcom Corporation
+ * Copyright (C) 1999-2014, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -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_roam.c 334946 2012-05-24 20:38:00Z $
+ * $Id: wl_roam.c 464529 2014-03-25 06:02:53Z $
*/
#include <typedefs.h>
@@ -29,7 +29,9 @@
#include <bcmwifi_channels.h>
#include <wlioctl.h>
#include <bcmutils.h>
+#ifdef WL_CFG80211
#include <wl_cfg80211.h>
+#endif
#include <wldev_common.h>
#define MAX_ROAM_CACHE 100
@@ -53,10 +55,37 @@ typedef struct {
static int n_roam_cache = 0;
static int roam_band = WLC_BAND_AUTO;
static roam_channel_cache roam_cache[MAX_ROAM_CACHE];
+static uint band2G, band5G, band_bw;
#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
static int roamscan_mode = ROAMSCAN_MODE_NORMAL;
#endif
+void init_roam(int ioctl_ver)
+{
+#ifdef D11AC_IOTYPES
+ if (ioctl_ver == 1) {
+ /* legacy chanspec */
+ band2G = WL_LCHANSPEC_BAND_2G;
+ band5G = WL_LCHANSPEC_BAND_5G;
+ band_bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
+ } else {
+ band2G = WL_CHANSPEC_BAND_2G;
+ band5G = WL_CHANSPEC_BAND_5G;
+ band_bw = WL_CHANSPEC_BW_20;
+ }
+#else
+ band2G = WL_CHANSPEC_BAND_2G;
+ band5G = WL_CHANSPEC_BAND_5G;
+ band_bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
+#endif /* D11AC_IOTYPES */
+
+ n_roam_cache = 0;
+ roam_band = WLC_BAND_AUTO;
+#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
+ roamscan_mode = ROAMSCAN_MODE_NORMAL;
+#endif
+}
+
#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
int get_roamscan_mode(struct net_device *dev, int *mode)
{
@@ -101,36 +130,18 @@ int set_roamscan_channel_list(struct net_device *dev,
int error;
channel_list_t channel_list;
char iobuf[WLC_IOCTL_SMLEN];
- uint band2G, band5G, bw;
roamscan_mode = ROAMSCAN_MODE_WES;
if (n > MAX_CHANNEL_LIST)
n = MAX_CHANNEL_LIST;
-#ifdef D11AC_IOTYPES
- if (ioctl_ver == 1) {
- /* legacy chanspec */
- band2G = WL_LCHANSPEC_BAND_2G;
- band5G = WL_LCHANSPEC_BAND_5G;
- bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
- } else {
- band2G = WL_CHANSPEC_BAND_2G;
- band5G = WL_CHANSPEC_BAND_5G;
- bw = WL_CHANSPEC_BW_20;
- }
-#else
- band2G = WL_CHANSPEC_BAND_2G;
- band5G = WL_CHANSPEC_BAND_5G;
- bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
-#endif /* D11AC_IOTYPES */
-
for (i = 0; i < n; i++) {
chanspec_t chanspec;
if (channels[i] <= CH_MAX_2G_CHANNEL) {
- chanspec = band2G | bw | channels[i];
+ chanspec = band2G | band_bw | channels[i];
} else {
- chanspec = band5G | bw | channels[i];
+ chanspec = band5G | band_bw | channels[i];
}
roam_cache[i].chanspec = chanspec;
channel_list.channels[i] = chanspec;
@@ -142,8 +153,8 @@ int set_roamscan_channel_list(struct net_device *dev,
channel_list.n = n;
/* need to set ROAMSCAN_MODE_NORMAL to update roamscan_channels,
- otherwise, it won't be updated
- */
+ * otherwise, it won't be updated
+ */
wldev_iovar_setint(dev, "roamscan_mode", ROAMSCAN_MODE_NORMAL);
error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
@@ -198,58 +209,49 @@ void add_roam_cache(wl_bss_info_t *bi)
WL_DBG(("CHSPEC 0x%X %d, CTL %d\n",
bi->chanspec, CHSPEC_CHANNEL(bi->chanspec), bi->ctl_ch));
roam_cache[n_roam_cache].chanspec =
- WL_CHANSPEC_BW_20 |
- (channel <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G) |
- channel;
+ (channel <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw | channel;
memcpy(roam_cache[n_roam_cache].ssid, bi->SSID, bi->SSID_len);
n_roam_cache++;
}
+static bool is_duplicated_channel(const chanspec_t *channels, int n_channels, chanspec_t new)
+{
+ int i;
+
+ for (i = 0; i < n_channels; i++) {
+ if (channels[i] == new)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
int get_roam_channel_list(int target_chan,
chanspec_t *channels, const wlc_ssid_t *ssid, int ioctl_ver)
{
int i, n = 1;
- uint band, band2G, band5G, bw;
-#ifdef D11AC_IOTYPES
- if (ioctl_ver == 1) {
- /* legacy chanspec */
- band2G = WL_LCHANSPEC_BAND_2G;
- band5G = WL_LCHANSPEC_BAND_5G;
- bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
- } else {
- band2G = WL_CHANSPEC_BAND_2G;
- band5G = WL_CHANSPEC_BAND_5G;
- bw = WL_CHANSPEC_BW_20;
- }
-#else
- band2G = WL_CHANSPEC_BAND_2G;
- band5G = WL_CHANSPEC_BAND_5G;
- bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
-#endif /* D11AC_IOTYPES */
+ /* first index is filled with the given target channel */
+ channels[0] = (target_chan & WL_CHANSPEC_CHAN_MASK) |
+ (target_chan <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw;
- if (target_chan <= CH_MAX_2G_CHANNEL)
- band = band2G;
- else
- band = band5G;
- *channels = (target_chan & WL_CHANSPEC_CHAN_MASK) | band | bw;
- WL_DBG(("%02d 0x%04X\n", target_chan, *channels));
- ++channels;
+ WL_DBG((" %s: %03d 0x%04X\n", __FUNCTION__, target_chan, channels[0]));
#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
if (roamscan_mode == ROAMSCAN_MODE_WES) {
for (i = 0; i < n_roam_cache; i++) {
- if ((roam_cache[i].chanspec & WL_CHANSPEC_CHAN_MASK) != target_chan) {
- *channels = roam_cache[i].chanspec & WL_CHANSPEC_CHAN_MASK;
- WL_DBG(("%02d\n", *channels));
- if (*channels <= CH_MAX_2G_CHANNEL)
- *channels |= band2G | bw;
- else
- *channels |= band5G | bw;
-
- channels++;
- n++;
+ chanspec_t ch = roam_cache[i].chanspec;
+ bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch);
+ bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch);
+ bool band_match = ((roam_band == WLC_BAND_AUTO) ||
+ ((roam_band == WLC_BAND_2G) && is_2G) ||
+ ((roam_band == WLC_BAND_5G) && is_5G));
+
+ ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw;
+ if (band_match && !is_duplicated_channel(channels, n, ch)) {
+ WL_DBG((" %s: %03d(0x%X)\n", __FUNCTION__, CHSPEC_CHANNEL(ch), ch));
+ channels[n++] = ch;
}
}
@@ -259,22 +261,20 @@ int get_roam_channel_list(int target_chan,
for (i = 0; i < n_roam_cache; i++) {
chanspec_t ch = roam_cache[i].chanspec;
+ bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch);
+ bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch);
+ bool band_match = ((roam_band == WLC_BAND_AUTO) ||
+ ((roam_band == WLC_BAND_2G) && is_2G) ||
+ ((roam_band == WLC_BAND_5G) && is_5G));
+
+ ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw;
if ((roam_cache[i].ssid_len == ssid->SSID_len) &&
- ((ch & WL_CHANSPEC_CHAN_MASK) != target_chan) &&
- ((roam_band == WLC_BAND_AUTO) ||
- ((roam_band == WLC_BAND_2G) && CHSPEC_IS2G(ch)) ||
- ((roam_band == WLC_BAND_5G) && CHSPEC_IS5G(ch))) &&
+ band_match && !is_duplicated_channel(channels, n, ch) &&
(memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) {
/* match found, add it */
- *channels = ch & WL_CHANSPEC_CHAN_MASK;
- if (*channels <= CH_MAX_2G_CHANNEL)
- *channels |= band2G | bw;
- else
- *channels |= band5G | bw;
-
- WL_DBG(("%02d 0x%04X\n", ch & WL_CHANSPEC_CHAN_MASK, *channels));
-
- channels++; n++;
+ WL_DBG((" %s: %03d(0x%04X)\n", __FUNCTION__,
+ CHSPEC_CHANNEL(ch), ch));
+ channels[n++] = ch;
}
}
@@ -286,7 +286,7 @@ void print_roam_cache(void)
{
int i;
- WL_DBG(("%d cache\n", n_roam_cache));
+ WL_DBG((" %d cache\n", n_roam_cache));
for (i = 0; i < n_roam_cache; i++) {
roam_cache[i].ssid[roam_cache[i].ssid_len] = 0;
@@ -314,14 +314,13 @@ static void add_roamcache_channel(channel_list_t *channels, chanspec_t ch)
ch & WL_CHANSPEC_CHAN_MASK, ch));
}
-void update_roam_cache(struct wl_priv *wl, int ioctl_ver)
+void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver)
{
int error, i, prev_channels;
channel_list_t channel_list;
char iobuf[WLC_IOCTL_SMLEN];
- struct net_device *dev = wl_to_prmry_ndev(wl);
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
wlc_ssid_t ssid;
- uint band2G, band5G, bw;
#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
if (roamscan_mode == ROAMSCAN_MODE_WES) {
@@ -330,7 +329,7 @@ void update_roam_cache(struct wl_priv *wl, int ioctl_ver)
}
#endif
- if (!wl_get_drv_status(wl, CONNECTED, dev)) {
+ if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
WL_DBG(("Not associated\n"));
return;
}
@@ -349,38 +348,19 @@ void update_roam_cache(struct wl_priv *wl, int ioctl_ver)
return;
}
-#ifdef D11AC_IOTYPES
- if (ioctl_ver == 1) {
- /* legacy chanspec */
- band2G = WL_LCHANSPEC_BAND_2G;
- band5G = WL_LCHANSPEC_BAND_5G;
- bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
- } else {
- band2G = WL_CHANSPEC_BAND_2G;
- band5G = WL_CHANSPEC_BAND_5G;
- bw = WL_CHANSPEC_BW_20;
- }
-#else
- band2G = WL_CHANSPEC_BAND_2G;
- band5G = WL_CHANSPEC_BAND_5G;
- bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
-#endif /* D11AC_IOTYPES */
-
prev_channels = channel_list.n;
for (i = 0; i < n_roam_cache; i++) {
chanspec_t ch = roam_cache[i].chanspec;
+ bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch);
+ bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch);
+ bool band_match = ((roam_band == WLC_BAND_AUTO) ||
+ ((roam_band == WLC_BAND_2G) && is_2G) ||
+ ((roam_band == WLC_BAND_5G) && is_5G));
+
if ((roam_cache[i].ssid_len == ssid.SSID_len) &&
- ((roam_band == WLC_BAND_AUTO) ||
- ((roam_band == WLC_BAND_2G) && CHSPEC_IS2G(ch)) ||
- ((roam_band == WLC_BAND_5G) && CHSPEC_IS5G(ch))) &&
- (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) {
+ band_match && (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) {
/* match found, add it */
- ch &= WL_CHANSPEC_CHAN_MASK;
- if (ch <= CH_MAX_2G_CHANNEL)
- ch |= band2G | bw;
- else
- ch |= band5G | bw;
-
+ ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw;
add_roamcache_channel(&channel_list, ch);
}
}
@@ -393,3 +373,52 @@ void update_roam_cache(struct wl_priv *wl, int ioctl_ver)
}
}
}
+
+void wl_update_roamscan_cache_by_band(struct net_device *dev, int band)
+{
+ int i, error, ioctl_ver, wes_mode;
+ channel_list_t chanlist_before, chanlist_after;
+ char iobuf[WLC_IOCTL_SMLEN];
+
+ roam_band = band;
+ if (band == WLC_BAND_AUTO)
+ return;
+
+ error = wldev_iovar_getint(dev, "roamscan_mode", &wes_mode);
+ if (error) {
+ WL_ERR(("Failed to get roamscan mode, error = %d\n", error));
+ return;
+ }
+ /* in case of WES mode, then skip the update */
+ if (wes_mode)
+ return;
+
+ error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
+ (void *)&chanlist_before, sizeof(channel_list_t), NULL);
+ if (error) {
+ WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
+ return;
+ }
+ ioctl_ver = wl_cfg80211_get_ioctl_version();
+ chanlist_after.n = 0;
+ /* filtering by the given band */
+ for (i = 0; i < chanlist_before.n; i++) {
+ chanspec_t chspec = chanlist_before.channels[i];
+ bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(chspec) : CHSPEC_IS2G(chspec);
+ bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(chspec) : CHSPEC_IS5G(chspec);
+ bool band_match = ((band == WLC_BAND_2G) && is_2G) ||
+ ((band == WLC_BAND_5G) && is_5G);
+ if (band_match) {
+ chanlist_after.channels[chanlist_after.n++] = chspec;
+ }
+ }
+
+ if (chanlist_before.n == chanlist_after.n)
+ return;
+
+ error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after,
+ sizeof(channel_list_t), iobuf, sizeof(iobuf), NULL);
+ if (error) {
+ WL_ERR(("Failed to update roamscan channels, error = %d\n", error));
+ }
+}