aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2012-12-19 12:56:39 -0800
committerZiyan <jaraidaniel@gmail.com>2016-05-01 23:35:11 +0200
commit1456f0fbca72df2b67cd86a688d9c59ea374a0b6 (patch)
tree962b9f4cd2f70ec0ec91f3e6898c7ba849ebe875
parentb14eb80091a3f11a69448bafc63a5501c613a487 (diff)
downloadkernel_samsung_tuna-1456f0fbca72df2b67cd86a688d9c59ea374a0b6.zip
kernel_samsung_tuna-1456f0fbca72df2b67cd86a688d9c59ea374a0b6.tar.gz
kernel_samsung_tuna-1456f0fbca72df2b67cd86a688d9c59ea374a0b6.tar.bz2
net: wireless: bcmdhd: Update to Version 1.28-23
- Add locale support via NL80211_CMD_REQ_SET_REG - Fix P2P and VSDB - Move setting for KEEP_ALIVE and PNO_LOCK into Makefile as CUSTOM_PNO_EVENT_LOCK_xTIME and CUSTOM_KEEP_ALIVE_SETTING Change-Id: I4d2e7c1c72f1109cc9ca3c79b07ad76aea1fd513 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile13
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c7
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c18
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c8
-rw-r--r--drivers/net/wireless/bcmdhd/bcmwifi_channels.c507
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h52
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cdc.c233
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cfg80211.c31
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c70
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c197
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c115
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_wlfc.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdpcm.h29
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h251
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h16
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmevent.h481
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlfc_proto.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h28
-rw-r--r--drivers/net/wireless/bcmdhd/linux_osl.c16
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c4
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c847
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h43
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c140
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h24
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.c4
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.h4
26 files changed, 2195 insertions, 949 deletions
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index aeacb5b..8514953 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -1,11 +1,5 @@
-# bcmdhd
-# -DDHDTHREAD -DDHD_GPL -DDHD_SCHED -DDHD_DEBUG -DSDTEST -DBDC -DTOE \
-# -DDHD_BCMEVENTS -DSHOW_EVENTS -DDONGLEOVERLAYS -DBCMDBG \
-# -DCUSTOMER_HW2 -DOOB_INTR_ONLY -DHW_OOB \
-# -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \
-# -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \
-# -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \
-# -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \
+# bcmdhd for 43241
+#
DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
-DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \
@@ -19,6 +13,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
-DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DROAM_ENABLE -DVSDB \
-DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX \
-DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET -DSUPPORT_PM2_ONLY \
+ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \
-DCUSTOM_SDIO_F2_BLKSIZE=128 \
-Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
@@ -38,6 +33,8 @@ bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o
DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF
DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65
DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15
+DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
+DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7
endif
ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),)
DHDCFLAGS += -DWL_SCHED_SCAN
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index b754703..3585948 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -20,7 +20,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* 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: bcmevent.c 327460 2012-04-13 18:38:41Z $
+ * $Id: bcmevent.c 370587 2012-11-22 09:32:38Z $
*/
#include <typedefs.h>
@@ -29,7 +29,7 @@
#include <proto/bcmeth.h>
#include <proto/bcmevent.h>
-#if WLC_E_LAST != 94
+#if WLC_E_LAST != 107
#error "You need to add an entry to bcmevent_names[] for the new event"
#endif
@@ -139,6 +139,9 @@ const bcmevent_name_t bcmevent_names[] = {
#ifdef WLTDLS
{ WLC_E_TDLS_PEER_EVENT, "TDLS_PEER_EVENT" },
#endif /* WLTDLS */
+ { WLC_E_SERVICE_FOUND, "SERVICE_FOUND" },
+ { WLC_E_P2PO_ADD_DEVICE, "P2PO_DEV_FOUND" },
+ { WLC_E_P2PO_DEL_DEVICE, "P2PO_DEV_LOST" },
};
const int bcmevent_names_size = ARRAYSIZE(bcmevent_names);
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index e724b78..180336a 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.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: bcmsdh_sdmmc.c 347640 2012-07-27 11:53:21Z $
+ * $Id: bcmsdh_sdmmc.c 362913 2012-10-15 11:26:11Z $
*/
#include <typedefs.h>
@@ -895,7 +895,7 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add
/* Claim host controller */
sdio_claim_host(gInstance->func[func]);
- if(rw) { /* CMD52 Write */
+ if(rw) { /* CMD53 Write */
if (nbytes == 4) {
sdio_writel(gInstance->func[func], *word, addr, &err_ret);
} else if (nbytes == 2) {
@@ -955,6 +955,7 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
void *pnext, *pprev;
uint ttl_len, dma_len, lft_len, xfred_len, pkt_len;
uint blk_num;
+ int blk_size;
struct mmc_request mmc_req;
struct mmc_command mmc_cmd;
struct mmc_data mmc_dat;
@@ -970,12 +971,13 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext))
ttl_len += PKTLEN(sd->osh, pnext);
- if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) {
+ blk_size = sd->client_block_size[func];
+ if (!sd->use_rxchain || ttl_len <= blk_size) {
blk_num = 0;
dma_len = 0;
} else {
- blk_num = ttl_len / sd->client_block_size[func];
- dma_len = blk_num * sd->client_block_size[func];
+ blk_num = ttl_len / blk_size;
+ dma_len = blk_num * blk_size;
}
lft_len = ttl_len - dma_len;
@@ -1016,7 +1018,7 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
mmc_dat.sg = sd->sg_list;
mmc_dat.sg_len = SGCount;
- mmc_dat.blksz = sd->client_block_size[func];
+ mmc_dat.blksz = blk_size;
mmc_dat.blocks = blk_num;
mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
@@ -1072,8 +1074,8 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
*/
if (write == 0 || pkt_len < 32)
pkt_len = (pkt_len + 3) & 0xFFFFFFFC;
- else if (pkt_len % DHD_SDALIGN)
- pkt_len += DHD_SDALIGN - (pkt_len % DHD_SDALIGN);
+ else if (pkt_len % blk_size)
+ pkt_len += blk_size - (pkt_len % blk_size);
#ifdef CONFIG_MMC_MSM7X00A
if ((pkt_len % 64) == 32) {
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
index a3e8ca9..079a89f 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.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: bcmsdh_sdmmc_linux.c 355594 2012-09-07 10:22:02Z $
+ * $Id: bcmsdh_sdmmc_linux.c 363783 2012-10-19 06:27:14Z $
*/
#include <typedefs.h>
@@ -153,10 +153,12 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func)
sd_info(("sdio_device: 0x%04x\n", func->device));
sd_info(("Function#: 0x%04x\n", func->num));
- if (func->num == 2) {
+ if (gInstance->func[2]) {
sd_trace(("F2 found, calling bcmsdh_remove...\n"));
bcmsdh_remove(&func->dev);
- } else if (func->num == 1) {
+ gInstance->func[2] = NULL;
+ }
+ if (func->num == 1) {
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c
index 0a570f6..6b5b0a3 100644
--- a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c
+++ b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c
@@ -40,27 +40,54 @@
#ifndef ASSERT
#define ASSERT(exp)
#endif
-#endif
+#endif /* BCMDRIVER */
#ifdef _bcmwifi_c_
-
+/* temporary for transitional compatibility */
#include <bcmwifi.h>
#else
#include <bcmwifi_channels.h>
#endif
#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
-#include <bcmstdlib.h>
+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
#endif
#ifndef D11AC_IOTYPES
+/* Definitions for legacy Chanspec type */
+/* Chanspec ASCII representation:
+ * <channel><band><bandwidth><ctl-sideband>
+ * digit [AB] [N] [UL]
+ *
+ * <channel>: channel number of the 10MHz or 20MHz channel,
+ * or control sideband channel of 40MHz channel.
+ * <band>: A for 5GHz, B for 2.4GHz
+ * <bandwidth>: N for 10MHz, nothing for 20MHz or 40MHz
+ * (ctl-sideband spec implies 40MHz)
+ * <ctl-sideband>: U for upper, L for lower
+ *
+ * <band> may be omitted on input, and will be assumed to be
+ * 2.4GHz if channel number <= 14.
+ *
+ * Examples:
+ * 8 -> 2.4GHz channel 8, 20MHz
+ * 8b -> 2.4GHz channel 8, 20MHz
+ * 8l -> 2.4GHz channel 8, 40MHz, lower ctl sideband
+ * 8a -> 5GHz channel 8 (low 5 GHz band), 20MHz
+ * 36 -> 5GHz channel 36, 20MHz
+ * 36l -> 5GHz channel 36, 40MHz, lower ctl sideband
+ * 40u -> 5GHz channel 40, 40MHz, upper ctl sideband
+ * 180n -> channel 180, 10MHz
+ */
-
-
-
+/* given a chanspec and a string buffer, format the chanspec as a
+ * string, and return the original pointer a.
+ * Min buffer length must be CHANSPEC_STR_LEN.
+ * On error return NULL
+ */
char *
wf_chspec_ntoa(chanspec_t chspec, char *buf)
{
@@ -71,7 +98,7 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf)
bw = "";
sb = "";
channel = CHSPEC_CHANNEL(chspec);
-
+ /* check for non-default band spec */
if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) ||
(CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL))
band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
@@ -87,12 +114,14 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf)
bw = "n";
}
-
+ /* Outputs a max of 6 chars including '\0' */
snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
return (buf);
}
-
+/* given a chanspec string, convert to a chanspec.
+ * On error return 0
+ */
chanspec_t
wf_chspec_aton(const char *a)
{
@@ -102,7 +131,7 @@ wf_chspec_aton(const char *a)
channel = strtoul(a, &endp, 10);
-
+ /* check for no digits parsed */
if (endp == a)
return 0;
@@ -119,7 +148,7 @@ wf_chspec_aton(const char *a)
if (c == '\0')
goto done;
-
+ /* parse the optional ['A' | 'B'] band spec */
if (c == 'a' || c == 'b') {
band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
a++;
@@ -128,13 +157,13 @@ wf_chspec_aton(const char *a)
goto done;
}
-
+ /* parse bandwidth 'N' (10MHz) or 40MHz ctl sideband ['L' | 'U'] */
if (c == 'n') {
bw = WL_CHANSPEC_BW_10;
} else if (c == 'l') {
bw = WL_CHANSPEC_BW_40;
ctl_sb = WL_CHANSPEC_CTL_SB_LOWER;
-
+ /* adjust channel to center of 40MHz band */
if (channel <= (MAXCHANNEL - CH_20MHZ_APART))
channel += CH_10MHZ_APART;
else
@@ -142,7 +171,7 @@ wf_chspec_aton(const char *a)
} else if (c == 'u') {
bw = WL_CHANSPEC_BW_40;
ctl_sb = WL_CHANSPEC_CTL_SB_UPPER;
-
+ /* adjust channel to center of 40MHz band */
if (channel > CH_20MHZ_APART)
channel -= CH_10MHZ_APART;
else
@@ -155,18 +184,23 @@ done:
return (channel | band | bw | ctl_sb);
}
-
+/*
+ * Verify the chanspec is using a legal set of parameters, i.e. that the
+ * chanspec specified a band, bw, ctl_sb and channel and that the
+ * combination could be legal given any set of circumstances.
+ * RETURNS: TRUE is the chanspec is malformed, false if it looks good.
+ */
bool
wf_chspec_malformed(chanspec_t chanspec)
{
-
+ /* must be 2G or 5G band */
if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
return TRUE;
-
+ /* must be 20 or 40 bandwidth */
if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
return TRUE;
-
+ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
if (CHSPEC_IS20(chanspec)) {
if (!CHSPEC_SB_NONE(chanspec))
return TRUE;
@@ -178,25 +212,31 @@ wf_chspec_malformed(chanspec_t chanspec)
return FALSE;
}
-
+/*
+ * This function returns the channel number that control traffic is being sent on, for legacy
+ * channels this is just the channel number, for 40MHZ channels it is the upper or lower 20MHZ
+ * sideband depending on the chanspec selected
+ */
uint8
wf_chspec_ctlchan(chanspec_t chspec)
{
uint8 ctl_chan;
-
+ /* Is there a sideband ? */
if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
return CHSPEC_CHANNEL(chspec);
} else {
-
+ /* we only support 40MHZ with sidebands */
ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40);
-
+ /* chanspec channel holds the centre frequency, use that and the
+ * side band information to reconstruct the control channel number
+ */
if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) {
-
+ /* control chan is the upper 20 MHZ SB of the 40MHZ channel */
ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
} else {
ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER);
-
+ /* control chan is the lower 20 MHZ SB of the 40MHZ channel */
ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
}
}
@@ -212,7 +252,7 @@ wf_chspec_ctlchspec(chanspec_t chspec)
ASSERT(!wf_chspec_malformed(chspec));
-
+ /* Is there a sideband ? */
if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
return chspec;
} else {
@@ -227,13 +267,76 @@ wf_chspec_ctlchspec(chanspec_t chspec)
return ctl_chspec;
}
-#else
-
-
-
+#else /* D11AC_IOTYPES */
+/* Definitions for D11AC capable Chanspec type */
+/* Chanspec ASCII representation with 802.11ac capability:
+ * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
+ *
+ * <band>:
+ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively.
+ * Default value is 2g if channel <= 14, otherwise 5g.
+ * <channel>:
+ * channel number of the 5MHz, 10MHz, 20MHz channel,
+ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel.
+ * <bandwidth>:
+ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20.
+ * <primary-sideband>:
+ * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower.
+ *
+ * For 2.4GHz band 40MHz channels, the same primary channel may be the
+ * upper sideband for one 40MHz channel, and the lower sideband for an
+ * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel
+ * is being specified.
+ *
+ * For 40MHz in the 5GHz band and all channel bandwidths greater than
+ * 40MHz, the U/L specificaion is not allowed since the channels are
+ * non-overlapping and the primary sub-band is derived from its
+ * position in the wide bandwidth channel.
+ *
+ * <1st80Channel>:
+ * <2nd80Channel>:
+ * Required for 80+80, otherwise not allowed.
+ * Specifies the center channel of the first and second 80MHz band.
+ *
+ * In its simplest form, it is a 20MHz channel number, with the implied band
+ * of 2.4GHz if channel number <= 14, and 5GHz otherwise.
+ *
+ * To allow for backward compatibility with scripts, the old form for
+ * 40MHz channels is also allowed: <channel><ctl-sideband>
+ *
+ * <channel>:
+ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz
+ * <ctl-sideband>:
+ * "U" for upper, "L" for lower (or lower case "u" "l")
+ *
+ * 5 GHz Examples:
+ * Chanspec BW Center Ch Channel Range Primary Ch
+ * 5g8 20MHz 8 - -
+ * 52 20MHz 52 - -
+ * 52/40 40MHz 54 52-56 52
+ * 56/40 40MHz 54 52-56 56
+ * 52/80 80MHz 58 52-64 52
+ * 56/80 80MHz 58 52-64 56
+ * 60/80 80MHz 58 52-64 60
+ * 64/80 80MHz 58 52-64 64
+ * 52/160 160MHz 50 36-64 52
+ * 36/160 160MGz 50 36-64 36
+ * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36
+ *
+ * 2 GHz Examples:
+ * Chanspec BW Center Ch Channel Range Primary Ch
+ * 2g8 20MHz 8 - -
+ * 8 20MHz 8 - -
+ * 6 20MHz 6 - -
+ * 6/40l 40MHz 8 6-10 6
+ * 6l 40MHz 8 6-10 6
+ * 6/40u 40MHz 4 2-6 6
+ * 6u 40MHz 4 2-6 6
+ */
+/* bandwidth ASCII string */
static const char *wf_chspec_bw_str[] =
{
"5",
@@ -252,26 +355,26 @@ static const uint8 wf_chspec_bw_mhz[] =
#define WF_NUM_BW \
(sizeof(wf_chspec_bw_mhz)/sizeof(uint8))
-
+/* 40MHz channels in 5GHz band */
static const uint8 wf_5g_40m_chans[] =
{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159};
#define WF_NUM_5G_40M_CHANS \
(sizeof(wf_5g_40m_chans)/sizeof(uint8))
-
+/* 80MHz channels in 5GHz band */
static const uint8 wf_5g_80m_chans[] =
{42, 58, 106, 122, 138, 155};
#define WF_NUM_5G_80M_CHANS \
(sizeof(wf_5g_80m_chans)/sizeof(uint8))
-
+/* 160MHz channels in 5GHz band */
static const uint8 wf_5g_160m_chans[] =
{50, 114};
#define WF_NUM_5G_160M_CHANS \
(sizeof(wf_5g_160m_chans)/sizeof(uint8))
-
+/* convert bandwidth from chanspec to MHz */
static uint
bw_chspec_to_mhz(chanspec_t chspec)
{
@@ -281,22 +384,31 @@ bw_chspec_to_mhz(chanspec_t chspec)
return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]);
}
-
+/* bw in MHz, return the channel count from the center channel to the
+ * the channel at the edge of the band
+ */
static uint8
center_chan_to_edge(uint bw)
{
-
+ /* edge channels separated by BW - 10MHz on each side
+ * delta from cf to edge is half of that,
+ * MHz to channel num conversion is 5MHz/channel
+ */
return (uint8)(((bw - 20) / 2) / 5);
}
-
+/* return channel number of the low edge of the band
+ * given the center channel and BW
+ */
static uint8
channel_low_edge(uint center_ch, uint bw)
{
return (uint8)(center_ch - center_chan_to_edge(bw));
}
-
+/* return side band number given center channel and control channel
+ * return -1 on error
+ */
static int
channel_to_sb(uint center_ch, uint ctl_ch, uint bw)
{
@@ -304,29 +416,31 @@ channel_to_sb(uint center_ch, uint ctl_ch, uint bw)
uint sb;
if ((ctl_ch - lowest) % 4) {
-
+ /* bad ctl channel, not mult 4 */
return -1;
}
sb = ((ctl_ch - lowest) / 4);
-
+ /* sb must be a index to a 20MHz channel in range */
if (sb >= (bw / 20)) {
-
+ /* ctl_ch must have been too high for the center_ch */
return -1;
}
return sb;
}
-
+/* return control channel given center channel and side band */
static uint8
channel_to_ctl_chan(uint center_ch, uint bw, uint sb)
{
return (uint8)(channel_low_edge(center_ch, bw) + sb * 4);
}
-
+/* return index of 80MHz channel from channel number
+ * return -1 on error
+ */
static int
channel_80mhz_to_id(uint ch)
{
@@ -339,7 +453,11 @@ channel_80mhz_to_id(uint ch)
return -1;
}
-
+/* given a chanspec and a string buffer, format the chanspec as a
+ * string, and return the original pointer a.
+ * Min buffer length must be CHANSPEC_STR_LEN.
+ * On error return NULL
+ */
char *
wf_chspec_ntoa(chanspec_t chspec, char *buf)
{
@@ -351,15 +469,15 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf)
band = "";
-
+ /* check for non-default band spec */
if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) ||
(CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL))
band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g";
-
+ /* ctl channel */
ctl_chan = wf_chspec_ctlchan(chspec);
-
+ /* bandwidth and ctl sideband */
if (CHSPEC_IS20(chspec)) {
snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan);
} else if (!CHSPEC_IS8080(chspec)) {
@@ -369,32 +487,32 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf)
bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT];
#ifdef CHANSPEC_NEW_40MHZ_FORMAT
-
+ /* ctl sideband string if needed for 2g 40MHz */
if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) {
sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
}
snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb);
#else
-
+ /* ctl sideband string instead of BW for 40MHz */
if (CHSPEC_IS40(chspec)) {
sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb);
} else {
snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw);
}
-#endif
+#endif /* CHANSPEC_NEW_40MHZ_FORMAT */
} else {
-
+ /* 80+80 */
uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT;
uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT;
-
+ /* convert to channel number */
chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0;
chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0;
-
+ /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */
snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2);
}
@@ -408,19 +526,21 @@ read_uint(const char **p, unsigned int *num)
char *endp = NULL;
val = strtoul(*p, &endp, 10);
-
+ /* if endp is the initial pointer value, then a number was not read */
if (endp == *p)
return 0;
-
+ /* advance the buffer pointer to the end of the integer string */
*p = endp;
-
+ /* return the parsed integer */
*num = (unsigned int)val;
return 1;
}
-
+/* given a chanspec string, convert to a chanspec.
+ * On error return 0
+ */
chanspec_t
wf_chspec_aton(const char *a)
{
@@ -435,16 +555,16 @@ wf_chspec_aton(const char *a)
chspec_sb = 0;
chspec_ch = ch1 = ch2 = 0;
-
+ /* parse channel num or band */
if (!read_uint(&a, &num))
return 0;
-
+ /* if we are looking at a 'g', then the first number was a band */
c = tolower(a[0]);
if (c == 'g') {
- a ++;
+ a ++; /* consume the char */
-
+ /* band must be "2" or "5" */
if (num == 2)
chspec_band = WL_CHANSPEC_BAND_2G;
else if (num == 5)
@@ -452,43 +572,43 @@ wf_chspec_aton(const char *a)
else
return 0;
-
+ /* read the channel number */
if (!read_uint(&a, &ctl_ch))
return 0;
c = tolower(a[0]);
}
else {
-
+ /* first number is channel, use default for band */
ctl_ch = num;
chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ?
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
}
if (c == '\0') {
-
+ /* default BW of 20MHz */
chspec_bw = WL_CHANSPEC_BW_20;
goto done_read;
}
- a ++;
+ a ++; /* consume the 'u','l', or '/' */
-
+ /* check 'u'/'l' */
if (c == 'u' || c == 'l') {
sb_ul = c;
chspec_bw = WL_CHANSPEC_BW_40;
goto done_read;
}
-
+ /* next letter must be '/' */
if (c != '/')
return 0;
-
+ /* read bandwidth */
if (!read_uint(&a, &bw))
return 0;
-
+ /* convert to chspec value */
if (bw == 20) {
chspec_bw = WL_CHANSPEC_BW_20;
} else if (bw == 40) {
@@ -501,63 +621,75 @@ wf_chspec_aton(const char *a)
return 0;
}
-
+ /* So far we have <band>g<chan>/<bw>
+ * Can now be followed by u/l if bw = 40,
+ * or '+80' if bw = 80, to make '80+80' bw.
+ */
c = tolower(a[0]);
-
+ /* if we have a 2g/40 channel, we should have a l/u spec now */
if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) {
if (c == 'u' || c == 'l') {
- a ++;
+ a ++; /* consume the u/l char */
sb_ul = c;
goto done_read;
}
}
-
+ /* check for 80+80 */
if (c == '+') {
-
+ /* 80+80 */
static const char *plus80 = "80/";
-
+ /* must be looking at '+80/'
+ * check and consume this string.
+ */
chspec_bw = WL_CHANSPEC_BW_8080;
- a ++;
+ a ++; /* consume the char '+' */
-
+ /* consume the '80/' string */
for (i = 0; i < 3; i++) {
if (*a++ != *plus80++) {
return 0;
}
}
-
+ /* read primary 80MHz channel */
if (!read_uint(&a, &ch1))
return 0;
-
+ /* must followed by '-' */
if (a[0] != '-')
return 0;
- a ++;
+ a ++; /* consume the char */
-
+ /* read secondary 80MHz channel */
if (!read_uint(&a, &ch2))
return 0;
}
done_read:
-
+ /* skip trailing white space */
while (a[0] == ' ') {
a ++;
}
-
+ /* must be end of string */
if (a[0] != '\0')
return 0;
-
+ /* Now have all the chanspec string parts read;
+ * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2.
+ * chspec_band and chspec_bw are chanspec values.
+ * Need to convert ctl_ch, sb_ul, and ch1,ch2 into
+ * a center channel (or two) and sideband.
+ */
-
+ /* if a sb u/l string was given, just use that,
+ * guaranteed to be bw = 40 by sting parse.
+ */
if (sb_ul != '\0') {
if (sb_ul == 'l') {
chspec_ch = UPPER_20_SB(ctl_ch);
@@ -567,14 +699,16 @@ done_read:
chspec_sb = WL_CHANSPEC_CTL_SB_LLU;
}
}
-
+ /* if the bw is 20, center and sideband are trivial */
else if (chspec_bw == WL_CHANSPEC_BW_20) {
chspec_ch = ctl_ch;
chspec_sb = 0;
}
-
+ /* if the bw is 40/80/160, not 80+80, a single method
+ * can be used to to find the center and sideband
+ */
else if (chspec_bw != WL_CHANSPEC_BW_8080) {
-
+ /* figure out ctl sideband based on ctl channel and bandwidth */
const uint8 *center_ch = NULL;
int num_ch = 0;
int sb = -1;
@@ -601,12 +735,12 @@ done_read:
}
}
-
+ /* check for no matching sb/center */
if (sb < 0) {
return 0;
}
}
-
+ /* Otherwise, bw is 80+80. Figure out channel pair and sb */
else {
int ch1_id = 0, ch2_id = 0;
int sb;
@@ -614,26 +748,28 @@ done_read:
ch1_id = channel_80mhz_to_id(ch1);
ch2_id = channel_80mhz_to_id(ch2);
-
+ /* validate channels */
if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0)
return 0;
-
+ /* combined channel in chspec */
chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
-
+ /* figure out ctl sideband */
-
+ /* does the primary channel fit with the 1st 80MHz channel ? */
sb = channel_to_sb(ch1, ctl_ch, bw);
if (sb < 0) {
-
+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
sb = channel_to_sb(ch2, ctl_ch, bw);
if (sb < 0) {
-
+ /* no match for ctl_ch to either 80MHz center channel */
return 0;
}
-
+ /* sb index is 0-3 for the low 80MHz channel, and 4-7 for
+ * the high 80MHz channel. Add 4 to to shift to high set.
+ */
sb += 4;
}
@@ -648,16 +784,21 @@ done_read:
return chspec;
}
-
+/*
+ * Verify the chanspec is using a legal set of parameters, i.e. that the
+ * chanspec specified a band, bw, ctl_sb and channel and that the
+ * combination could be legal given any set of circumstances.
+ * RETURNS: TRUE is the chanspec is malformed, false if it looks good.
+ */
bool
wf_chspec_malformed(chanspec_t chanspec)
{
uint chspec_bw = CHSPEC_BW(chanspec);
uint chspec_ch = CHSPEC_CHANNEL(chanspec);
-
+ /* must be 2G or 5G band */
if (CHSPEC_IS2G(chanspec)) {
-
+ /* must be valid bandwidth */
if (chspec_bw != WL_CHANSPEC_BW_20 &&
chspec_bw != WL_CHANSPEC_BW_40) {
return TRUE;
@@ -666,13 +807,13 @@ wf_chspec_malformed(chanspec_t chanspec)
if (chspec_bw == WL_CHANSPEC_BW_8080) {
uint ch1_id, ch2_id;
-
+ /* channel number in 80+80 must be in range */
ch1_id = CHSPEC_CHAN1(chanspec);
ch2_id = CHSPEC_CHAN2(chanspec);
if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS)
return TRUE;
-
+ /* ch2 must be above ch1 for the chanspec */
if (ch2_id <= ch1_id)
return TRUE;
} else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
@@ -682,15 +823,15 @@ wf_chspec_malformed(chanspec_t chanspec)
return TRUE;
}
} else {
-
+ /* invalid bandwidth */
return TRUE;
}
} else {
-
+ /* must be 2G or 5G band */
return TRUE;
}
-
+ /* side band needs to be consistent with bandwidth */
if (chspec_bw == WL_CHANSPEC_BW_20) {
if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL)
return TRUE;
@@ -705,7 +846,10 @@ wf_chspec_malformed(chanspec_t chanspec)
return FALSE;
}
-
+/*
+ * Verify the chanspec specifies a valid channel according to 802.11.
+ * RETURNS: TRUE if the chanspec is a valid 802.11 channel
+ */
bool
wf_chspec_valid(chanspec_t chanspec)
{
@@ -716,7 +860,7 @@ wf_chspec_valid(chanspec_t chanspec)
return FALSE;
if (CHSPEC_IS2G(chanspec)) {
-
+ /* must be valid bandwidth and channel range */
if (chspec_bw == WL_CHANSPEC_BW_20) {
if (chspec_ch >= 1 && chspec_ch <= 14)
return TRUE;
@@ -731,7 +875,9 @@ wf_chspec_valid(chanspec_t chanspec)
ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)];
ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)];
-
+ /* the two channels must be separated by more than 80MHz by VHT req,
+ * and ch2 above ch1 for the chanspec
+ */
if (ch2 > ch1 + CH_80MHZ_APART)
return TRUE;
} else {
@@ -748,35 +894,38 @@ wf_chspec_valid(chanspec_t chanspec)
center_ch = wf_5g_160m_chans;
num_ch = WF_NUM_5G_160M_CHANS;
} else {
-
+ /* invalid bandwidth */
return FALSE;
}
-
+ /* check for a valid center channel */
if (chspec_bw == WL_CHANSPEC_BW_20) {
-
+ /* We don't have an array of legal 20MHz 5G channels, but they are
+ * each side of the legal 40MHz channels. Check the chanspec
+ * channel against either side of the 40MHz channels.
+ */
for (i = 0; i < num_ch; i ++) {
if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) ||
chspec_ch == (uint)UPPER_20_SB(center_ch[i]))
- break;
+ break; /* match found */
}
if (i == num_ch) {
-
+ /* check for legacy JP channels on failure */
if (chspec_ch == 34 || chspec_ch == 38 ||
chspec_ch == 42 || chspec_ch == 46)
i = 0;
}
} else {
-
+ /* check the chanspec channel to each legal channel */
for (i = 0; i < num_ch; i ++) {
if (chspec_ch == center_ch[i])
- break;
+ break; /* match found */
}
}
if (i < num_ch) {
-
+ /* match found */
return TRUE;
}
}
@@ -785,7 +934,11 @@ wf_chspec_valid(chanspec_t chanspec)
return FALSE;
}
-
+/*
+ * This function returns the channel number that control traffic is being sent on, for 20MHz
+ * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ
+ * sideband depending on the chanspec selected
+ */
uint8
wf_chspec_ctlchan(chanspec_t chspec)
{
@@ -795,7 +948,7 @@ wf_chspec_ctlchan(chanspec_t chspec)
ASSERT(!wf_chspec_malformed(chspec));
-
+ /* Is there a sideband ? */
if (CHSPEC_IS20(chspec)) {
return CHSPEC_CHANNEL(chspec);
} else {
@@ -812,7 +965,7 @@ wf_chspec_ctlchan(chanspec_t chspec)
sb -= 4;
}
-
+ /* convert from channel index to channel number */
center_chan = wf_5g_80m_chans[center_chan];
}
else {
@@ -824,7 +977,9 @@ wf_chspec_ctlchan(chanspec_t chspec)
}
}
-
+/*
+ * This function returns the chanspec of the control channel of a given chanspec
+ */
chanspec_t
wf_chspec_ctlchspec(chanspec_t chspec)
{
@@ -833,7 +988,7 @@ wf_chspec_ctlchspec(chanspec_t chspec)
ASSERT(!wf_chspec_malformed(chspec));
-
+ /* Is there a sideband ? */
if (!CHSPEC_IS20(chspec)) {
ctl_chan = wf_chspec_ctlchan(chspec);
ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20;
@@ -842,9 +997,64 @@ wf_chspec_ctlchspec(chanspec_t chspec)
return ctl_chspec;
}
-#endif
+/* return chanspec given control channel and bandwidth
+ * return 0 on error
+ */
+uint16
+wf_channel2chspec(uint ctl_ch, uint bw)
+{
+ uint16 chspec;
+ const uint8 *center_ch = NULL;
+ int num_ch = 0;
+ int sb = -1;
+ int i = 0;
+
+ chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
+
+ chspec |= bw;
+
+ if (bw == WL_CHANSPEC_BW_40) {
+ center_ch = wf_5g_40m_chans;
+ num_ch = WF_NUM_5G_40M_CHANS;
+ bw = 40;
+ } else if (bw == WL_CHANSPEC_BW_80) {
+ center_ch = wf_5g_80m_chans;
+ num_ch = WF_NUM_5G_80M_CHANS;
+ bw = 80;
+ } else if (bw == WL_CHANSPEC_BW_160) {
+ center_ch = wf_5g_160m_chans;
+ num_ch = WF_NUM_5G_160M_CHANS;
+ bw = 160;
+ } else if (bw == WL_CHANSPEC_BW_20) {
+ chspec |= ctl_ch;
+ return chspec;
+ } else {
+ return 0;
+ }
+ for (i = 0; i < num_ch; i ++) {
+ sb = channel_to_sb(center_ch[i], ctl_ch, bw);
+ if (sb >= 0) {
+ chspec |= center_ch[i];
+ chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT);
+ break;
+ }
+ }
+
+ /* check for no matching sb/center */
+ if (sb < 0) {
+ return 0;
+ }
+ return chspec;
+}
+#endif /* D11AC_IOTYPES */
+
+/*
+ * This function returns the chanspec for the primary 40MHz of an 80MHz channel.
+ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using
+ * as the primary 20MHz channel.
+ */
extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
{
chanspec_t chspec40 = chspec;
@@ -858,20 +1068,20 @@ extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
sb = CHSPEC_CTL_SB(chspec);
if (sb == WL_CHANSPEC_CTL_SB_UL) {
-
+ /* Primary 40MHz is on upper side */
sb = WL_CHANSPEC_CTL_SB_L;
center_chan += CH_20MHZ_APART;
} else if (sb == WL_CHANSPEC_CTL_SB_UU) {
-
+ /* Primary 40MHz is on upper side */
sb = WL_CHANSPEC_CTL_SB_U;
center_chan += CH_20MHZ_APART;
} else {
-
-
+ /* Primary 40MHz is on lower side */
+ /* sideband bits are the same for LL/LU and L/U */
center_chan -= CH_20MHZ_APART;
}
-
+ /* Create primary 40MHz chanspec */
chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 |
sb | center_chan);
}
@@ -879,7 +1089,25 @@ extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
return chspec40;
}
-
+/*
+ * Return the channel number for a given frequency and base frequency.
+ * The returned channel number is relative to the given base frequency.
+ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
+ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
+ *
+ * Frequency is specified in MHz.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
+ * 2.4 GHz and 5 GHz bands.
+ *
+ * The returned channel will be in the range [1, 14] in the 2.4 GHz band
+ * and [0, 200] otherwise.
+ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
+ * frequency is not a 2.4 GHz channel, or if the frequency is not and even
+ * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ */
int
wf_mhz2channel(uint freq, uint start_factor)
{
@@ -887,7 +1115,7 @@ wf_mhz2channel(uint freq, uint start_factor)
uint base;
int offset;
-
+ /* take the default channel start frequency */
if (start_factor == 0) {
if (freq >= 2400 && freq <= 2500)
start_factor = WF_CHAN_FACTOR_2_4_G;
@@ -900,25 +1128,40 @@ wf_mhz2channel(uint freq, uint start_factor)
base = start_factor / 2;
-
+ /* check that the frequency is in 1GHz range of the base */
if ((freq < base) || (freq > base + 1000))
return -1;
offset = freq - base;
ch = offset / 5;
-
+ /* check that frequency is a 5MHz multiple from the base */
if (offset != (ch * 5))
return -1;
-
+ /* restricted channel range check for 2.4G */
if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
return -1;
return ch;
}
-
+/*
+ * Return the center frequency in MHz of the given channel and base frequency.
+ * The channel number is interpreted relative to the given base frequency.
+ *
+ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G
+ * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands.
+ * The channel range of [1, 14] is only checked for a start_factor of
+ * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2).
+ * Odd start_factors produce channels on .5 MHz boundaries, in which case
+ * the answer is rounded down to an integral MHz.
+ * -1 is returned for an out of range channel.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ */
int
wf_channel2mhz(uint ch, uint start_factor)
{
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index 6db8bd6..8a1e3d2 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -24,7 +24,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: dhd.h 356711 2012-09-13 15:58:32Z $
+ * $Id: dhd.h 373887 2012-12-10 21:58:02Z $
*/
/****************
@@ -93,14 +93,14 @@ enum dhd_op_flags {
#endif
#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */
-#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */
+#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */
#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */
#ifndef POWERUP_MAX_RETRY
#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */
#endif
#ifndef POWERUP_WAIT_MS
-#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */
+#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */
#endif
enum dhd_bus_wake_state {
@@ -230,8 +230,10 @@ typedef struct dhd_pub {
int pno_enable; /* pno status : "1" is pno enable */
int pno_suspend; /* pno suspend status : "1" is pno suspended */
#endif /* PNO_SUPPORT */
- int dtim_skip; /* dtim skip , default 0 means wake each dtim */
-
+ /* DTIM skip value, default 0(or 1) means wake each DTIM
+ * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3)
+ */
+ int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */
#ifdef PKT_FILTER_SUPPORT
int early_suspended; /* Early suspend status */
int dhcp_in_progress; /* DHCP period */
@@ -271,6 +273,9 @@ typedef struct dhd_pub {
uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */
#endif
struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS];
+#if defined(ARP_OFFLOAD_SUPPORT)
+ uint32 arp_version;
+#endif
} dhd_pub_t;
@@ -497,7 +502,7 @@ extern int net_os_enable_packet_filter(struct net_device *dev, int val);
extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
#endif /* PKT_FILTER_SUPPORT */
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
extern bool dhd_support_sta_mode(dhd_pub_t *dhd);
#ifdef DHD_DEBUG
@@ -565,10 +570,6 @@ extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp);
extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
#endif /* KEEP_ALIVE */
-#ifdef ARP_OFFLOAD_SUPPORT
-extern void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode);
-extern void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable);
-#endif /* ARP_OFFLOAD_SUPPORT */
extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd);
typedef enum cust_gpio_modes {
@@ -635,8 +636,12 @@ extern uint dhd_sdiod_drive_strength;
/* Override to force tx queueing all the time */
extern uint dhd_force_tx_queueing;
-/* Default KEEP_ALIVE Period is 28 sec to prevent AP from sending Keep Alive probe frame */
-#define KEEP_ALIVE_PERIOD 28000
+/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */
+#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */
+#ifndef CUSTOM_KEEP_ALIVE_SETTING
+#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE
+#endif /* DEFAULT_KEEP_ALIVE_VALUE */
+
#define NULL_PKT_STR "null_pkt"
/* hooks for custom glom setting option via Makefile */
@@ -659,6 +664,13 @@ extern uint dhd_force_tx_queueing;
#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE
#endif
+/* hooks for custom PNO Event wake lock to guarantee enough time
+ for the Platform to detect Event before system suspended
+*/
+#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */
+#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME
+#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME
+#endif
/* hooks for custom dhd_dpc_prio setting option via Makefile */
#define DEFAULT_DHP_DPC_PRIO 1
@@ -666,6 +678,10 @@ extern uint dhd_force_tx_queueing;
#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO
#endif
+#define DEFAULT_SUSPEND_BCN_LI_DTIM 3
+#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM
+#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM
+#endif
#ifdef SDTEST
/* Echo packet generator (SDIO), pkts/s */
@@ -696,6 +712,7 @@ extern uint dhd_download_fw_on_driverload;
#define DHD_MAX_IFS 16
#define DHD_DEL_IF -0xe
#define DHD_BAD_IF -0xf
+#define WL_AUTO_ROAM_TRIGGER -75
#ifdef PROP_TXSTATUS
/* Please be mindful that total pkttag space is 32 octets only */
@@ -843,11 +860,14 @@ extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend);
#endif /* PNO_SUPPORT */
#ifdef ARP_OFFLOAD_SUPPORT
#define MAX_IPV4_ENTRIES 8
+void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode);
+void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable);
+
/* dhd_commn arp offload wrapers */
-void dhd_aoe_hostip_clr(dhd_pub_t *dhd);
-void dhd_aoe_arp_clr(dhd_pub_t *dhd);
-int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen);
-void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr);
+void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx);
+void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx);
+int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx);
+void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx);
#endif /* ARP_OFFLOAD_SUPPORT */
#endif /* _dhd_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
index fd10538..b51dbc6 100644
--- a/drivers/net/wireless/bcmdhd/dhd_cdc.c
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.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: dhd_cdc.c 355825 2012-09-10 03:22:40Z $
+ * $Id: dhd_cdc.c 368762 2012-11-14 21:59:17Z $
*
* BDC is like CDC, except it includes a header for data packets to convey
* packet priority over the bus, and flags (e.g. to indicate checksum status
@@ -668,13 +668,16 @@ dhd_wlfc_hanger_delete(osl_t *osh, void* hanger)
static uint16
dhd_wlfc_hanger_get_free_slot(void* hanger)
{
- int i;
+ uint32 i;
wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
if (h) {
- for (i = 0; i < h->max_items; i++) {
- if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE)
+ for (i = (h->slot_pos + 1); i != h->slot_pos;) {
+ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) {
+ h->slot_pos = i;
return (uint16)i;
+ }
+ (i == h->max_items)? i = 0 : i++;
}
h->failed_slotfind++;
}
@@ -1524,7 +1527,8 @@ _dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac,
ctx->stats.sendq_pkts[ac]++;
WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
}
- }
+ } else if (rc == BCME_NORESOURCE)
+ rc = BCME_ERROR;
else {
/*
bus commit has failed, rollback.
@@ -1760,6 +1764,7 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
int fifo_id;
dhd_os_wlfc_block(dhd);
+
if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) {
#ifdef PROP_TXSTATUS_DEBUG
wlfc->stats.signal_only_pkts_freed++;
@@ -1806,6 +1811,179 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
return;
}
+static int
+dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len)
+{
+ uint8 status_flag;
+ uint32 status;
+ int ret;
+ int remove_from_hanger = 1;
+ void* pktbuf;
+ uint8 fifo_id;
+ uint8 count = 0;
+ uint32 status_g;
+ uint32 hslot, hcnt;
+ wlfc_mac_descriptor_t* entry = NULL;
+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
+ dhd->wlfc_state;
+
+ memcpy(&status, pkt_info, sizeof(uint32));
+ status_flag = WL_TXSTATUS_GET_FLAGS(status);
+ status_g = status & 0xff000000;
+ hslot = (status & 0x00ffff00) >> 8;
+ hcnt = status & 0xff;
+ len = pkt_info[4];
+
+ wlfc->stats.txstatus_in++;
+
+ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) {
+ wlfc->stats.pkt_freed++;
+ }
+
+ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) {
+ wlfc->stats.d11_suppress++;
+ remove_from_hanger = 0;
+ }
+
+ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) {
+ wlfc->stats.wl_suppress++;
+ remove_from_hanger = 0;
+ }
+
+ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) {
+ wlfc->stats.wlc_tossed_pkts++;
+ }
+ while (count < len) {
+ status = (status_g << 24) | (hslot << 8) | (hcnt);
+ count++;
+ hslot++;
+ hcnt++;
+
+ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger,
+ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger);
+ if (ret != BCME_OK) {
+ /* do something */
+ continue;
+ }
+
+ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf);
+
+ if (!remove_from_hanger) {
+ /* this packet was suppressed */
+ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) {
+ entry->suppressed = TRUE;
+ entry->suppress_count = pktq_mlen(&entry->psq,
+ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1));
+ entry->suppr_transit_count = entry->transit_count;
+ }
+ entry->generation = WLFC_PKTID_GEN(status);
+ }
+
+#ifdef PROP_TXSTATUS_DEBUG
+ {
+ uint32 new_t = OSL_SYSUPTIME();
+ uint32 old_t;
+ uint32 delta;
+ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[
+ WLFC_PKTID_HSLOT_GET(status)].push_time;
+
+
+ wlfc->stats.latency_sample_count++;
+ if (new_t > old_t)
+ delta = new_t - old_t;
+ else
+ delta = 0xffffffff + new_t - old_t;
+ wlfc->stats.total_status_latency += delta;
+ wlfc->stats.latency_most_recent = delta;
+
+ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta;
+ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32))
+ wlfc->stats.idx_delta = 0;
+ }
+#endif /* PROP_TXSTATUS_DEBUG */
+
+ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf));
+
+ /* pick up the implicit credit from this packet */
+ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) {
+ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) {
+
+ int lender, credit_returned = 0; /* Note that borrower is fifo_id */
+
+ /* Return credits to highest priority lender first */
+ for (lender = AC_COUNT; lender >= 0; lender--) {
+ if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
+ wlfc->FIFO_credit[lender]++;
+ wlfc->credits_borrowed[fifo_id][lender]--;
+ credit_returned = 1;
+ break;
+ }
+ }
+
+ if (!credit_returned) {
+ wlfc->FIFO_credit[fifo_id]++;
+ }
+ }
+ }
+ else {
+ /*
+ if this packet did not count against FIFO credit, it must have
+ taken a requested_credit from the destination entry (for pspoll etc.)
+ */
+ if (!entry) {
+
+ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf);
+ }
+ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf)))
+ entry->requested_credit++;
+#ifdef PROP_TXSTATUS_DEBUG
+ entry->dstncredit_acks++;
+#endif
+ }
+ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) ||
+ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) {
+
+ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf);
+ if (ret != BCME_OK) {
+ /* delay q is full, drop this packet */
+ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status),
+ &pktbuf, 1);
+
+ /* indicate failure and free the packet */
+ dhd_txcomplete(dhd, pktbuf, FALSE);
+ entry->transit_count--;
+ /* packet is transmitted Successfully by dongle
+ * after first suppress.
+ */
+ if (entry->suppressed) {
+ entry->suppr_transit_count--;
+ }
+ PKTFREE(wlfc->osh, pktbuf, TRUE);
+ } else {
+ /* Mark suppressed to avoid a double free during wlfc cleanup */
+
+ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger,
+ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status));
+ entry->suppress_count++;
+ }
+ }
+ else {
+ dhd_txcomplete(dhd, pktbuf, TRUE);
+ entry->transit_count--;
+
+ /* This packet is transmitted Successfully by dongle
+ * even after first suppress.
+ */
+ if (entry->suppressed) {
+ entry->suppr_transit_count--;
+ }
+ /* free the packet */
+ PKTFREE(wlfc->osh, pktbuf, TRUE);
+ }
+ }
+ return BCME_OK;
+}
+
/* Handle discard or suppress indication */
static int
dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info)
@@ -2258,6 +2436,8 @@ dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar
processed += 2 + len;
if (type == WLFC_CTL_TYPE_TXSTATUS)
dhd_wlfc_txstatus_update(dhd, value);
+ if (type == WLFC_CTL_TYPE_COMP_TXSTATUS)
+ dhd_wlfc_compressed_txstatus_update(dhd, value, len);
else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS)
dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf,
@@ -2339,6 +2519,8 @@ dhd_wlfc_enable(dhd_pub_t *dhd)
int i;
athost_wl_status_info_t* wlfc;
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+
if (!dhd->wlfc_enabled || dhd->wlfc_state)
return BCME_OK;
@@ -2383,6 +2565,7 @@ dhd_wlfc_enable(dhd_pub_t *dhd)
wlfc->allow_credit_borrow = TRUE;
wlfc->borrow_defer_timestamp = 0;
+
return BCME_OK;
}
@@ -2399,10 +2582,13 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd)
int prec;
void *pkt = NULL;
struct pktq *txq = NULL;
+
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
if (dhd->wlfc_state == NULL)
return;
/* flush bus->txq */
txq = dhd_bus_txq(dhd->bus);
+
/* any in the hanger? */
h = (wlfc_hanger_t*)wlfc->hanger;
total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t);
@@ -2470,6 +2656,8 @@ dhd_wlfc_deinit(dhd_pub_t *dhd)
athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
dhd->wlfc_state;
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+
dhd_os_wlfc_block(dhd);
if (dhd->wlfc_state == NULL) {
dhd_os_wlfc_unblock(dhd);
@@ -2601,9 +2789,9 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in
#endif /* BDC */
#if !defined(NDIS630)
- if (PKTLEN(dhd->osh, pktbuf) < (uint32) (h->dataOffset << 2)) {
+ if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
- PKTLEN(dhd->osh, pktbuf), (h->dataOffset * 4)));
+ PKTLEN(dhd->osh, pktbuf), (data_offset * 4)));
return BCME_ERROR;
}
#endif
@@ -2616,21 +2804,34 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in
- parse txstatus only for packets that came from the firmware
*/
dhd_os_wlfc_block(dhd);
- dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2),
+ dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2),
reorder_buf_info, reorder_info_len);
((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++;
- dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
- (void *)dhd->bus);
dhd_os_wlfc_unblock(dhd);
}
#endif /* PROP_TXSTATUS */
exit:
#if !defined(NDIS630)
- PKTPULL(dhd->osh, pktbuf, (h->dataOffset << 2));
+ PKTPULL(dhd->osh, pktbuf, (data_offset << 2));
#endif
return 0;
}
+#if defined(PROP_TXSTATUS)
+void
+dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd)
+{
+ if (dhd->wlfc_state &&
+ (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode
+ != WLFC_FCMODE_NONE)) {
+ dhd_os_wlfc_block(dhd);
+ dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
+ (void *)dhd->bus);
+ dhd_os_wlfc_unblock(dhd);
+ }
+}
+#endif
+
int
dhd_prot_attach(dhd_pub_t *dhd)
{
@@ -2705,15 +2906,15 @@ dhd_prot_init(dhd_pub_t *dhd)
goto done;
-#ifdef PROP_TXSTATUS
- ret = dhd_wlfc_init(dhd);
-#endif
-
#if defined(WL_CFG80211)
if (dhd_download_fw_on_driverload)
#endif /* defined(WL_CFG80211) */
ret = dhd_preinit_ioctls(dhd);
+#ifdef PROP_TXSTATUS
+ ret = dhd_wlfc_init(dhd);
+#endif
+
/* Always assumes wl for now */
dhd->iswl = TRUE;
@@ -2747,7 +2948,7 @@ dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt,
i = ptr->max_idx + 1;
else {
if (start > end)
- i = (ptr->max_idx - end) + start;
+ i = ((ptr->max_idx + 1) - start) + end;
else
i = end - start;
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
index 073b407..03671c4 100644
--- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
@@ -82,9 +82,11 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val)
dhd->op_mode |= val;
WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
#ifdef ARP_OFFLOAD_SUPPORT
- /* IF P2P is enabled, disable arpoe */
- dhd_arp_offload_set(dhd, 0);
- dhd_arp_offload_enable(dhd, false);
+ if (dhd->arp_version == 1) {
+ /* IF P2P is enabled, disable arpoe */
+ dhd_arp_offload_set(dhd, 0);
+ dhd_arp_offload_enable(dhd, false);
+ }
#endif /* ARP_OFFLOAD_SUPPORT */
return 0;
@@ -97,9 +99,11 @@ s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl)
WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
#ifdef ARP_OFFLOAD_SUPPORT
- /* IF P2P is disabled, enable arpoe back for STA mode. */
- dhd_arp_offload_set(dhd, dhd_arp_mode);
- dhd_arp_offload_enable(dhd, true);
+ if (dhd->arp_version == 1) {
+ /* IF P2P is disabled, enable arpoe back for STA mode. */
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, true);
+ }
#endif /* ARP_OFFLOAD_SUPPORT */
return 0;
@@ -505,7 +509,7 @@ void wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
if (!wl->btcoex_info)
return;
- if (!wl->btcoex_info->timer_on) {
+ if (wl->btcoex_info->timer_on) {
wl->btcoex_info->timer_on = 0;
del_timer_sync(&wl->btcoex_info->timer);
}
@@ -547,10 +551,14 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
WL_TRACE_HW4(("%s: DHCP session starts\n", __FUNCTION__));
+#if defined(DHCP_SCAN_SUPPRESS)
+ /* Suppress scan during the DHCP */
+ wl_cfg80211_scan_suppress(dev, 1);
+#endif
+
#ifdef PKT_FILTER_SUPPORT
dhd->dhcp_in_progress = 1;
- /* Disable packet filtering */
if (dhd->early_suspended) {
WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
dhd_enable_packet_filter(0, dhd);
@@ -605,12 +613,17 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
dhd->dhcp_in_progress = 0;
WL_TRACE_HW4(("%s: DHCP is complete \n", __FUNCTION__));
+#if defined(DHCP_SCAN_SUPPRESS)
+ /* Since DHCP is complete, enable the scan back */
+ wl_cfg80211_scan_suppress(dev, 0);
+#endif
+
/* Enable packet filtering */
if (dhd->early_suspended) {
WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
dhd_enable_packet_filter(1, dhd);
}
-#endif
+#endif /* PKT_FILTER_SUPPORT */
/* Restoring PM mode */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 8edf461..c62e87c 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.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: dhd_common.c 356374 2012-09-12 10:37:44Z $
+ * $Id: dhd_common.c 373873 2012-12-10 20:45:58Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -949,6 +949,12 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
break;
+ case WLC_E_SERVICE_FOUND:
+ case WLC_E_P2PO_ADD_DEVICE:
+ case WLC_E_P2PO_DEL_DEVICE:
+ DHD_EVENT(("MACEVENT: %s, MAC: %s\n", event_name, eabuf));
+ break;
+
default:
DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
event_name, event_type, eabuf, (int)status, (int)reason,
@@ -1437,10 +1443,10 @@ dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
retcode = retcode >= 0 ? 0 : retcode;
if (retcode)
DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
- __FUNCTION__, arp_mode, retcode));
+ __FUNCTION__, arp_mode, retcode));
else
DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
- __FUNCTION__, arp_mode));
+ __FUNCTION__, arp_mode));
}
void
@@ -1454,49 +1460,73 @@ dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
retcode = retcode >= 0 ? 0 : retcode;
if (retcode)
DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
- __FUNCTION__, arp_enable, retcode));
+ __FUNCTION__, arp_enable, retcode));
else
DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
- __FUNCTION__, arp_enable));
+ __FUNCTION__, arp_enable));
+ if (arp_enable) {
+ uint32 version;
+ bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf));
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
+ if (retcode) {
+ DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
+ __FUNCTION__, retcode));
+ dhd->arp_version = 1;
+ }
+ else {
+ memcpy(&version, iovbuf, sizeof(version));
+ DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version));
+ dhd->arp_version = version;
+ }
+ }
}
void
-dhd_aoe_arp_clr(dhd_pub_t *dhd)
+dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx)
{
int ret = 0;
int iov_len = 0;
char iovbuf[128];
if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx) < 0))
DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
}
void
-dhd_aoe_hostip_clr(dhd_pub_t *dhd)
+dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
{
int ret = 0;
int iov_len = 0;
char iovbuf[128];
if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0)
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
}
void
-dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
+dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx)
{
int iov_len = 0;
char iovbuf[32];
int retcode;
- iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf));
- retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+ iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr,
+ sizeof(ipaddr), iovbuf, sizeof(iovbuf));
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
if (retcode)
DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
@@ -1507,7 +1537,7 @@ dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
}
int
-dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
+dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx)
{
int retcode, i;
int iov_len;
@@ -1516,10 +1546,13 @@ dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
if (!buf)
return -1;
+ if (dhd == NULL) return -1;
+ if (dhd->arp_version == 1)
+ idx = 0;
iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
BCM_REFERENCE(iov_len);
- retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0);
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx);
if (retcode) {
DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
@@ -1602,16 +1635,13 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
/* Function to estimate possible DTIM_SKIP value */
int
-dhd_get_dtim_skip(dhd_pub_t *dhd)
+dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
{
int bcn_li_dtim;
int ret = -1;
int dtim_assoc = 0;
- if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
- bcn_li_dtim = 3;
- else
- bcn_li_dtim = dhd->dtim_skip;
+ bcn_li_dtim = dhd->suspend_bcn_li_dtim;
/* Check if associated */
if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
@@ -1887,7 +1917,7 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd)
strncpy(buf, str, str_len);
buf[ str_len ] = '\0';
mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
- mkeep_alive_pkt.period_msec = KEEP_ALIVE_PERIOD;
+ mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING;
buf_len = str_len + 1;
mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 474e15a..4961194 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -22,7 +22,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: dhd_linux.c 358016 2012-09-20 22:36:51Z $
+ * $Id: dhd_linux.c 374275 2012-12-12 11:44:18Z $
*/
#include <typedefs.h>
@@ -95,10 +95,6 @@ typedef struct histo_ {
static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
#endif /* WLMEDIA_HTSF */
-#ifndef DTIM_COUNT
-#define DTIM_COUNT 3
-#endif
-
#if defined(PKT_FILTER_SUPPORT)
#endif /* PKT_FILTER_SUPPORT */
@@ -122,7 +118,7 @@ extern bool ap_fw_loaded;
#include <wl_android.h>
#ifdef ARP_OFFLOAD_SUPPORT
-void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add);
+void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
static int dhd_device_event(struct notifier_block *this,
unsigned long event,
void *ptr);
@@ -177,7 +173,8 @@ extern wl_iw_extra_params_t g_wl_iw_params;
#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
#ifdef PKT_FILTER_SUPPORT
extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
@@ -195,7 +192,7 @@ extern int dhd_write_rdwr_macaddr(struct ether_addr *mac);
extern int dhd_write_macaddr(struct ether_addr *mac);
#endif
#ifdef GET_MAC_FROM_OTP
-extern int dhd_check_module_mac(dhd_pub_t *dhd);
+extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac);
#endif
#ifdef MIMO_ANT_SETTING
extern int dhd_sel_ant_from_file(dhd_pub_t *dhd);
@@ -371,7 +368,7 @@ module_param(disable_proptx, int, 0644);
/* load firmware and/or nvram values from the filesystem */
module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
-module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
+module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
/* Watchdog interval */
uint dhd_watchdog_ms = 10;
@@ -569,7 +566,7 @@ extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
-static void dhd_set_packet_filter(dhd_pub_t *dhd)
+void dhd_set_packet_filter(dhd_pub_t *dhd)
{
#ifdef PKT_FILTER_SUPPORT
int i;
@@ -580,7 +577,7 @@ static void dhd_set_packet_filter(dhd_pub_t *dhd)
dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
}
}
-#endif
+#endif /* PKT_FILTER_SUPPORT */
}
void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
@@ -612,12 +609,12 @@ void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
static int dhd_set_suspend(int value, dhd_pub_t *dhd)
{
-#ifndef SUPPORT_PM2_ONLY
+#if !defined(SUPPORT_PM2_ONLY)
int power_mode = PM_MAX;
#endif
/* wl_pkt_filter_enable_t enable_parm; */
char iovbuf[32];
- int bcn_li_dtim = DTIM_COUNT;
+ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
#ifndef DISABLE_FW_ROAM_SUSPEND
uint roamvar = 1;
#endif
@@ -625,7 +622,9 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
int bcn_li_bcn;
#endif /* ENABLE_BCN_LI_BCN_WAKEUP */
#ifdef PASS_ALL_MCAST_PKTS
+ struct dhd_info *dhdinfo = dhd->info;
uint32 allmulti;
+ uint i;
#endif /* PASS_ALL_MCAST_PKTS */
DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
@@ -640,7 +639,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
/* Kernel suspended */
DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__));
-#ifndef SUPPORT_PM2_ONLY
+#if !defined(SUPPORT_PM2_ONLY)
dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
sizeof(power_mode), TRUE, 0);
#endif
@@ -650,14 +649,18 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
allmulti = 0;
bcm_mkiovar("allmulti", (char *)&allmulti,
4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net)
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, i);
+ }
#endif /* PASS_ALL_MCAST_PKTS */
/* If DTIM skip is set up as default, force it to wake
* each third DTIM for better power savings. Note that
* one side effect is a chance to miss BC/MC packet.
*/
- bcn_li_dtim = dhd_get_dtim_skip(dhd);
+ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
@@ -682,7 +685,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
/* Kernel resumed */
DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__));
-#ifndef SUPPORT_PM2_ONLY
+#if !defined(SUPPORT_PM2_ONLY)
power_mode = PM_FAST;
dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
sizeof(power_mode), TRUE, 0);
@@ -693,11 +696,15 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
allmulti = 1;
bcm_mkiovar("allmulti", (char *)&allmulti,
4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net)
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, i);
+ }
#endif /* PASS_ALL_MCAST_PKTS */
/* restore pre-suspend setting for dtim_skip */
- bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
@@ -917,6 +924,8 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
ASSERT(dhd && dhd->iflist[ifidx]);
dev = dhd->iflist[ifidx]->net;
+ if (!dev)
+ return;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
netif_addr_lock_bh(dev);
#endif
@@ -1373,7 +1382,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
}
/* Look into the packet and update the packet priority */
+#ifndef PKTPRIO_OVERRIDE
if (PKTPRIO(pktbuf) == 0)
+#endif
pktsetprio(pktbuf, FALSE);
#ifdef PROP_TXSTATUS
@@ -1400,9 +1411,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
dhd_htsf_addtxts(dhdp, pktbuf);
#endif
#ifdef PROP_TXSTATUS
+ dhd_os_wlfc_block(dhdp);
if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode
!= WLFC_FCMODE_NONE) {
- dhd_os_wlfc_block(dhdp);
ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)),
pktbuf);
dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
@@ -1412,9 +1423,11 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
}
dhd_os_wlfc_unblock(dhdp);
}
- else
+ else {
+ dhd_os_wlfc_unblock(dhdp);
/* non-proptxstatus way */
ret = dhd_bus_txdata(dhdp->bus, pktbuf);
+ }
#else
ret = dhd_bus_txdata(dhdp->bus, pktbuf);
#endif /* PROP_TXSTATUS */
@@ -1762,16 +1775,23 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
wl_event_to_host_order(&event);
if (!tout_ctrl)
tout_ctrl = DHD_PACKET_TIMEOUT_MS;
-#if defined(PNO_SUPPORT)
- if (event.event_type == WLC_E_PFN_NET_FOUND) {
- tout_ctrl = 7 * DHD_PACKET_TIMEOUT_MS;
- }
-#endif /* PNO_SUPPORT */
#ifdef WLBTAMP
if (event.event_type == WLC_E_BTA_HCI_EVENT) {
dhd_bta_doevt(dhdp, data, event.datalen);
}
#endif /* WLBTAMP */
+
+#if defined(PNO_SUPPORT)
+ if (event.event_type == WLC_E_PFN_NET_FOUND) {
+ /* enforce custom wake lock to garantee that Kernel not suspended */
+ tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
+ }
+#endif /* PNO_SUPPORT */
+
+#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ continue;
+#endif
} else {
tout_rx = DHD_PACKET_TIMEOUT_MS;
}
@@ -1916,6 +1936,8 @@ dhd_watchdog_thread(void *data)
while (1)
if (down_interruptible (&tsk->sema) == 0) {
unsigned long flags;
+ unsigned long jiffies_at_start = jiffies;
+ unsigned long time_lapse;
SMP_RD_BARRIER_DEPENDS();
if (tsk->terminated) {
@@ -1932,10 +1954,14 @@ dhd_watchdog_thread(void *data)
flags = dhd_os_spin_lock(&dhd->pub);
/* Count the tick for reference */
dhd->pub.tickcnt++;
+ time_lapse = jiffies - jiffies_at_start;
+
/* Reschedule the watchdog */
if (dhd->wd_timer_valid)
mod_timer(&dhd->timer,
- jiffies + msecs_to_jiffies(dhd_watchdog_ms));
+ jiffies +
+ msecs_to_jiffies(dhd_watchdog_ms) -
+ min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
dhd_os_spin_unlock(&dhd->pub, flags);
}
dhd_os_sdunlock(&dhd->pub);
@@ -2636,13 +2662,6 @@ dhd_open(struct net_device *net)
firmware_path[0] = '\0';
}
- /* Update NVRAM path if it was changed */
- if (!dhd_download_fw_on_driverload && (strlen(nvram_path) != 0)) {
- if (nvram_path[strlen(nvram_path)-1] == '\n')
- nvram_path[strlen(nvram_path)-1] = '\0';
- strcpy(nv_path, nvram_path);
- nvram_path[0] = '\0';
- }
dhd->pub.dongle_trap_occured = 0;
dhd->pub.hang_was_sent = 0;
@@ -3039,7 +3058,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
dhd->threads_only = FALSE;
}
- if (dhd_dpc_prio >= 0) {
+ if (dhd_watchdog_prio >= 0) {
/* Initialize watchdog thread */
PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0);
} else {
@@ -3228,7 +3247,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
#ifdef ARP_OFFLOAD_SUPPORT
if (dhd->pend_ipaddr) {
#ifdef AOE_IP_ALIAS_SUPPORT
- aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE);
+ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
#endif /* AOE_IP_ALIAS_SUPPORT */
dhd->pend_ipaddr = 0;
}
@@ -3382,6 +3401,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
uint32 hostreorder = 1;
#endif
#endif /* DISABLE_11N */
+ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
#ifdef PROP_TXSTATUS
#ifdef PROP_TXSTATUS_VSDB
dhd->wlfc_enabled = FALSE;
@@ -3638,8 +3658,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
setbit(eventmask, WLC_E_ESCAN_RESULT);
if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
setbit(eventmask, WLC_E_ACTION_FRAME_RX);
- setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE);
- setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE);
setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
}
#endif /* WL_CFG80211 */
@@ -3671,6 +3689,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd_arp_offload_enable(dhd, FALSE);
dhd_arp_offload_set(dhd, 0);
}
+ dhd_arp_enable = arpoe;
#endif /* ARP_OFFLOAD_SUPPORT */
#ifdef PKT_FILTER_SUPPORT
@@ -3796,7 +3815,7 @@ int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
#ifdef ARP_OFFLOAD_SUPPORT
/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
void
-aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
+aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
{
u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
int i;
@@ -3805,13 +3824,13 @@ aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
bzero(ipv4_buf, sizeof(ipv4_buf));
/* display what we've got */
- ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
+ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
#ifdef AOE_DBG
dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
#endif
/* now we saved hoste_ip table, clr it in the dongle AOE */
- dhd_aoe_hostip_clr(dhd_pub);
+ dhd_aoe_hostip_clr(dhd_pub, idx);
if (ret) {
DHD_ERROR(("%s failed\n", __FUNCTION__));
@@ -3832,19 +3851,24 @@ aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
if (ipv4_buf[i] != 0) {
/* add back host_ip entries from our local cache */
- dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i]);
+ dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
__FUNCTION__, ipv4_buf[i], i));
}
}
#ifdef AOE_DBG
/* see the resulting hostip table */
- dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
+ dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
#endif
}
+/*
+ * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
+ * whenever there is an event related to an IP address.
+ * ptr : kernel provided pointer to IP address that has changed
+ */
static int dhd_device_event(struct notifier_block *this,
unsigned long event,
void *ptr)
@@ -3853,19 +3877,48 @@ static int dhd_device_event(struct notifier_block *this,
dhd_info_t *dhd;
dhd_pub_t *dhd_pub;
+ int idx;
- if (!ifa)
+ if (!dhd_arp_enable)
+ return NOTIFY_DONE;
+ if (!ifa || !(ifa->ifa_dev->dev))
return NOTIFY_DONE;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+ /* Filter notifications meant for non Broadcom devices */
+ if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
+ (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
+#ifdef WLP2P
+ if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
+#endif
+ return NOTIFY_DONE;
+ }
+#endif /* LINUX_VERSION_CODE */
+
dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev);
+ if (!dhd)
+ return NOTIFY_DONE;
+
dhd_pub = &dhd->pub;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
- if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) {
-#else
- if (ifa->ifa_dev->dev) {
-#endif
- switch (event) {
+ if (dhd_pub->arp_version == 1) {
+ idx = 0;
+ }
+ else {
+ for (idx = 0; idx < DHD_MAX_IFS; idx++) {
+ if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
+ break;
+ }
+ if (idx < DHD_MAX_IFS)
+ DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
+ dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
+ else {
+ DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
+ idx = 0;
+ }
+ }
+
+ switch (event) {
case NETDEV_UP:
DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
@@ -3881,16 +3934,9 @@ static int dhd_device_event(struct notifier_block *this,
}
#ifdef AOE_IP_ALIAS_SUPPORT
- if (!(dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE)) {
- if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) {
- /* 0x3a = ':' */
- DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
- __FUNCTION__));
- aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
- }
- else
- aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
- }
+ DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
+ __FUNCTION__));
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
#endif
break;
@@ -3899,20 +3945,12 @@ static int dhd_device_event(struct notifier_block *this,
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
dhd->pend_ipaddr = 0;
#ifdef AOE_IP_ALIAS_SUPPORT
- if (!(dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE)) {
- if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
- /* 0x3a = ':' */
- DHD_ARPOE(("%s: primary interface is down,"
- " AOE clr all\n", __FUNCTION__));
- dhd_aoe_hostip_clr(&dhd->pub);
- dhd_aoe_arp_clr(&dhd->pub);
- } else
- aoe_update_host_ipv4_table(dhd_pub,
- ifa->ifa_address, FALSE);
- }
+ DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
+ __FUNCTION__));
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
#else
- dhd_aoe_hostip_clr(&dhd->pub);
- dhd_aoe_arp_clr(&dhd->pub);
+ dhd_aoe_hostip_clr(&dhd->pub, idx);
+ dhd_aoe_arp_clr(&dhd->pub, idx);
#endif /* AOE_IP_ALIAS_SUPPORT */
break;
@@ -3920,7 +3958,6 @@ static int dhd_device_event(struct notifier_block *this,
DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
__func__, ifa->ifa_label, event));
break;
- }
}
return NOTIFY_DONE;
}
@@ -4798,7 +4835,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
struct dhd_info *dhdinfo = dhd->info;
- int timeout = msecs_to_jiffies(2000);
+ int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT);
dhd_os_sdunlock(dhd);
wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
dhd_os_sdlock(dhd);
@@ -4869,12 +4906,12 @@ int net_os_set_suspend(struct net_device *dev, int val, int force)
return ret;
}
-int net_os_set_dtim_skip(struct net_device *dev, int val)
+int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd)
- dhd->pub.dtim_skip = val;
+ dhd->pub.suspend_bcn_li_dtim = val;
return 0;
}
@@ -5041,14 +5078,14 @@ int net_os_send_hang_message(struct net_device *dev)
}
#endif
-void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
+void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd && dhd->pub.up) {
memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
#ifdef WL_CFG80211
- wl_update_wiphybands(NULL);
+ wl_update_wiphybands(NULL, notify);
#endif
}
}
@@ -5058,7 +5095,7 @@ void dhd_bus_band_set(struct net_device *dev, uint band)
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd && dhd->pub.up) {
#ifdef WL_CFG80211
- wl_update_wiphybands(NULL);
+ wl_update_wiphybands(NULL, true);
#endif
}
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 1c2fe1f..c5ecafc 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.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: dhd_sdio.c 357859 2012-09-20 06:34:26Z $
+ * $Id: dhd_sdio.c 373330 2012-12-07 04:46:17Z $
*/
#include <typedefs.h>
@@ -152,6 +152,7 @@ extern void bcmsdh_set_irq(int flag);
#endif /* defined(OOB_INTR_ONLY) */
#ifdef PROP_TXSTATUS
extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
+extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
@@ -301,6 +302,13 @@ typedef struct dhd_bus {
uint pktgen_ptick; /* Burst counter for printing */
uint pktgen_sent; /* Number of test packets generated */
uint pktgen_rcvd; /* Number of test packets received */
+ uint pktgen_prev_time; /* Time at which previous stats where printed */
+ uint pktgen_prev_sent; /* Number of test packets generated when
+ * previous stats were printed
+ */
+ uint pktgen_prev_rcvd; /* Number of test packets received when
+ * previous stats were printed
+ */
uint pktgen_fail; /* Number of failed send attempts */
uint16 pktgen_len; /* Length of next packet to send */
#define PKTGEN_RCV_IDLE (0)
@@ -524,7 +532,7 @@ do { \
#ifdef SDTEST
static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
-static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
+static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
#endif
#ifdef DHD_DEBUG
@@ -1000,6 +1008,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
bus->kso = on ? FALSE : TRUE;
else {
DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
+ if (!on && retry > 2)
+ bus->kso = TRUE;
}
return err;
@@ -1718,7 +1728,13 @@ done:
dhd_os_sdlock(bus->dhd);
} else {
#endif /* PROP_TXSTATUS */
+#ifdef SDTEST
+ if (chan != SDPCM_TEST_CHANNEL) {
+ dhd_txcomplete(bus->dhd, pkt, ret != 0);
+ }
+#else /* SDTEST */
dhd_txcomplete(bus->dhd, pkt, ret != 0);
+#endif /* SDTEST */
if (free_pkt)
PKTFREE(osh, pkt, TRUE);
@@ -2118,9 +2134,10 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
ret = 0;
} else {
bus->dhd->txcnt_timeout++;
- if (!bus->dhd->hang_was_sent)
+ if (!bus->dhd->hang_was_sent) {
DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
__FUNCTION__, bus->dhd->txcnt_timeout));
+ }
ret = -1;
bus->ctrl_frame_stat = FALSE;
goto done;
@@ -2523,12 +2540,15 @@ dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
bus->pktgen_stop = pktgen.stop;
bus->pktgen_tick = bus->pktgen_ptick = 0;
+ bus->pktgen_prev_time = jiffies;
bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
/* Clear counts for a new pktgen (mode change, or was stopped) */
- if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
- bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
+ if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
+ bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
+ bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
+ }
return 0;
}
@@ -5509,7 +5529,7 @@ dhdsdio_hostmail(dhd_bus_t *bus)
#ifdef DHD_DEBUG
/* At least print a message if FW halted */
if (hmb_data & HMB_DATA_FWHALT) {
- DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
+ DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
dhdsdio_checkdied(bus, NULL, 0);
bus->dhd->busstate = DHD_BUS_DOWN;
}
@@ -5708,7 +5728,7 @@ clkwait:
__FUNCTION__, rxdone, framecnt));
bus->intdis = FALSE;
#if defined(OOB_INTR_ONLY)
- bcmsdh_oob_intr_set(1);
+ bcmsdh_oob_intr_set(1);
#endif /* defined(OOB_INTR_ONLY) */
bcmsdh_intr_enable(sdh);
}
@@ -5728,7 +5748,9 @@ clkwait:
resched = TRUE;
}
#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
-
+#ifdef PROP_TXSTATUS
+ dhd_wlfc_trigger_pktcommit(bus->dhd);
+#endif
if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
int ret, i;
@@ -5925,19 +5947,37 @@ dhdsdio_pktgen(dhd_bus_t *bus)
uint fillbyte;
osl_t *osh = bus->dhd->osh;
uint16 len;
+ ulong time_lapse;
+ uint sent_pkts;
+ uint rcvd_pkts;
/* Display current count if appropriate */
if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
bus->pktgen_ptick = 0;
- printf("%s: send attempts %d rcvd %d\n",
- __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
+ printf("%s: send attempts %d, rcvd %d, errors %d\n",
+ __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
+
+ /* Print throughput stats only for constant length packet runs */
+ if (bus->pktgen_minlen == bus->pktgen_maxlen) {
+ time_lapse = jiffies - bus->pktgen_prev_time;
+ bus->pktgen_prev_time = jiffies;
+ sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
+ bus->pktgen_prev_sent = bus->pktgen_sent;
+ rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
+ bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
+
+ printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
+ __FUNCTION__,
+ (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
+ (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
+ }
}
/* For recv mode, just make sure dongle has started sending */
if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
- dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total);
+ dhdsdio_sdtest_set(bus, bus->pktgen_total);
}
return;
}
@@ -5951,7 +5991,11 @@ dhdsdio_pktgen(dhd_bus_t *bus)
}
/* Allocate an appropriate-sized packet */
- len = bus->pktgen_len;
+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
+ len = SDPCM_TEST_PKT_CNT_FLD_LEN;
+ } else {
+ len = bus->pktgen_len;
+ }
if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
TRUE))) {;
DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
@@ -5974,7 +6018,7 @@ dhdsdio_pktgen(dhd_bus_t *bus)
case DHD_PKTGEN_RXBURST:
*data++ = SDPCM_TEST_BURST;
- *data++ = (uint8)bus->pktgen_count;
+ *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
break;
default:
@@ -5985,12 +6029,23 @@ dhdsdio_pktgen(dhd_bus_t *bus)
}
/* Write test header length field */
- *data++ = (len >> 0);
- *data++ = (len >> 8);
+ *data++ = (bus->pktgen_len >> 0);
+ *data++ = (bus->pktgen_len >> 8);
+
+ /* Write frame count in a 4 byte field adjucent to SDPCM test header for
+ * burst mode
+ */
+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
+ *data++ = (uint8)(bus->pktgen_count >> 0);
+ *data++ = (uint8)(bus->pktgen_count >> 8);
+ *data++ = (uint8)(bus->pktgen_count >> 16);
+ *data++ = (uint8)(bus->pktgen_count >> 24);
+ } else {
- /* Then fill in the remainder -- N/A for burst, but who cares... */
- for (fillbyte = 0; fillbyte < len; fillbyte++)
- *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
+ /* Then fill in the remainder -- N/A for burst */
+ for (fillbyte = 0; fillbyte < len; fillbyte++)
+ *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
+ }
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_DATA_ON()) {
@@ -6018,25 +6073,31 @@ dhdsdio_pktgen(dhd_bus_t *bus)
}
static void
-dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count)
+dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
{
void *pkt;
uint8 *data;
osl_t *osh = bus->dhd->osh;
/* Allocate the packet */
- if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
+ if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
+ SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
return;
}
- PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
+ PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
+ SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
/* Fill in the test header */
*data++ = SDPCM_TEST_SEND;
- *data++ = count;
+ *data++ = (count > 0)?TRUE:FALSE;
*data++ = (bus->pktgen_maxlen >> 0);
*data++ = (bus->pktgen_maxlen >> 8);
+ *data++ = (uint8)(count >> 0);
+ *data++ = (uint8)(count >> 8);
+ *data++ = (uint8)(count >> 16);
+ *data++ = (uint8)(count >> 24);
/* Send it */
if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
@@ -6238,7 +6299,10 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
/* Generate packets if configured */
if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
/* Make sure backplane clock is on */
- dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+ if (SLPAUTO_ENAB(bus))
+ dhdsdio_bussleep(bus, FALSE);
+ else
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
bus->pktgen_tick = 0;
dhdsdio_pktgen(bus);
}
@@ -6581,8 +6645,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
if (dhd_download_fw_on_driverload) {
if ((ret = dhd_bus_start(bus->dhd)) != 0) {
DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
- if (ret == BCME_NOTUP)
- goto fail;
+ goto fail;
}
}
/* Ok, have the per-port tell the stack we're open for business */
@@ -7025,10 +7088,10 @@ dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool r
return;
if (bus->sih) {
+#if !defined(BCMLXSDMMC)
if (bus->dhd) {
dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
}
-#if !defined(BCMLXSDMMC)
if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
si_watchdog(bus->sih, 4);
#endif /* !defined(BCMLXSDMMC) */
diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
index 4087351..5a64e6f 100644
--- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
@@ -18,7 +18,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* 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: dhd_wlfc.h 341930 2012-06-29 04:51:25Z $
+* $Id: dhd_wlfc.h 361006 2012-10-05 07:45:51Z $
*
*/
#ifndef __wlfc_host_driver_definitions_h__
@@ -85,6 +85,7 @@ typedef struct wlfc_hanger {
uint32 failed_to_pop;
uint32 failed_slotfind;
wlfc_hanger_item_t items[1];
+ uint32 slot_pos;
} wlfc_hanger_t;
#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
index 80c0a3d..fb2ec3a 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
@@ -22,7 +22,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: bcmsdpcm.h 291086 2011-10-21 01:17:24Z $
+ * $Id: bcmsdpcm.h 362722 2012-10-12 23:55:55Z $
*/
#ifndef _bcmsdpcm_h_
@@ -146,16 +146,23 @@
#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80)
/* For TEST_CHANNEL packets, define another 4-byte header */
-#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2);
- * Semantics of Ext byte depend on command.
- * Len is current or requested frame length, not
- * including test header; sent little-endian.
- */
-#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */
-#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */
-#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */
-#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count */
-#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off */
+#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2);
+ * Semantics of Ext byte depend on command.
+ * Len is current or requested frame length, not
+ * including test header; sent little-endian.
+ */
+#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */
+#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */
+#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */
+#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */
+#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count
+ * (Backward compatabilty) Set frame count in a
+ * 4 byte filed adjacent to the HDR
+ */
+#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off
+ * Set frame count in a 4 byte filed adjacent to
+ * the HDR
+ */
/* Handy macro for filling in datagen packets with a pattern */
#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno))
diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h
index c797047..bc57aca 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h
@@ -30,10 +30,10 @@
#define _bcmwifi_channels_h_
-
+/* A chanspec holds the channel number, band, bandwidth and control sideband */
typedef uint16 chanspec_t;
-
+/* channel defines */
#define CH_UPPER_SB 0x01
#define CH_LOWER_SB 0x02
#define CH_EWA_VALID 0x04
@@ -41,12 +41,15 @@ typedef uint16 chanspec_t;
#define CH_40MHZ_APART 8
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
-#define CH_5MHZ_APART 1
-#define CH_MAX_2G_CHANNEL 14
-#define MAXCHANNEL 224
+#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
+#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
+#define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216,
+ * this is that + 1 rounded up to a multiple of NBBY (8).
+ * DO NOT MAKE it > 255: channels are uint8's all over
+ */
#define CHSPEC_CTLOVLP(sp1, sp2, sep) ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep)
-
+/* All builds use the new 11ac ratespec/chanspec */
#undef D11AC_IOTYPES
#define D11AC_IOTYPES
@@ -69,11 +72,17 @@ typedef uint16 chanspec_t;
#define WL_CHANSPEC_BAND_MASK 0xf000
#define WL_CHANSPEC_BAND_SHIFT 12
+#ifdef WL_CHANSPEC_BAND_5G
+#undef WL_CHANSPEC_BAND_5G
+#endif
+#ifdef WL_CHANSPEC_BAND_2G
+#undef WL_CHANSPEC_BAND_2G
+#endif
#define WL_CHANSPEC_BAND_5G 0x1000
#define WL_CHANSPEC_BAND_2G 0x2000
#define INVCHANSPEC 255
-
+/* channel defines */
#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0)
#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
((channel) + CH_10MHZ_APART) : 0)
@@ -90,7 +99,7 @@ typedef uint16 chanspec_t;
#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
-
+/* chanspec stores radio channel & flags to indicate control channel location, i.e. upper/lower */
#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
@@ -102,7 +111,7 @@ typedef uint16 chanspec_t;
#define CHSPEC_IS40(chspec) 0
#endif
-#else
+#else /* !WL11N_20MHZONLY */
#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
@@ -110,7 +119,7 @@ typedef uint16 chanspec_t;
#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
#endif
-#endif
+#endif /* !WL11N_20MHZONLY */
#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
@@ -124,7 +133,7 @@ typedef uint16 chanspec_t;
#define CHANSPEC_STR_LEN 8
-#else
+#else /* D11AC_IOTYPES */
#define WL_CHANSPEC_CHAN_MASK 0x00ff
#define WL_CHANSPEC_CHAN_SHIFT 0
@@ -170,7 +179,7 @@ typedef uint16 chanspec_t;
#define WL_CHANSPEC_BAND_5G 0xc000
#define INVCHANSPEC 255
-
+/* channel defines */
#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \
((channel) - CH_10MHZ_APART) : 0)
#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
@@ -194,7 +203,7 @@ typedef uint16 chanspec_t;
((channel) | (ctlsb) | \
WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G)
-
+/* simple MACROs to get different fields of chanspec */
#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK)
#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK)
@@ -219,7 +228,7 @@ typedef uint16 chanspec_t;
#define CHSPEC_IS8080(chspec) 0
#endif
-#else
+#else /* !WL11N_20MHZONLY */
#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
@@ -236,7 +245,7 @@ typedef uint16 chanspec_t;
#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080)
#endif
-#endif
+#endif /* !WL11N_20MHZONLY */
#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
@@ -248,11 +257,15 @@ typedef uint16 chanspec_t;
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G)
-
+/**
+ * Number of chars needed for wf_chspec_ntoa() destination character buffer.
+ */
#define CHANSPEC_STR_LEN 20
-
+/* Legacy Chanspec defines
+ * These are the defines for the previous format of the chanspec_t
+ */
#define WL_LCHANSPEC_CHAN_MASK 0x00ff
#define WL_LCHANSPEC_CHAN_SHIFT 0
@@ -285,61 +298,193 @@ typedef uint16 chanspec_t;
#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band)))
-#endif
-
-
-
-
-#define WF_CHAN_FACTOR_2_4_G 4814
-
-
-#define WF_CHAN_FACTOR_5_G 10000
-
+#endif /* D11AC_IOTYPES */
-#define WF_CHAN_FACTOR_4_G 8000
-
-
-#define WLC_MAXRATE 108
-#define WLC_RATE_1M 2
-#define WLC_RATE_2M 4
-#define WLC_RATE_5M5 11
-#define WLC_RATE_11M 22
-#define WLC_RATE_6M 12
-#define WLC_RATE_9M 18
-#define WLC_RATE_12M 24
-#define WLC_RATE_18M 36
-#define WLC_RATE_24M 48
-#define WLC_RATE_36M 72
-#define WLC_RATE_48M 96
-#define WLC_RATE_54M 108
+/*
+ * WF_CHAN_FACTOR_* constants are used to calculate channel frequency
+ * given a channel number.
+ * chan_freq = chan_factor * 500Mhz + chan_number * 5
+ */
-#define WLC_2G_25MHZ_OFFSET 5
+/**
+ * Channel Factor for the starting frequence of 2.4 GHz channels.
+ * The value corresponds to 2407 MHz.
+ */
+#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
+/**
+ * Channel Factor for the starting frequence of 5 GHz channels.
+ * The value corresponds to 5000 MHz.
+ */
+#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
+/**
+ * Channel Factor for the starting frequence of 4.9 GHz channels.
+ * The value corresponds to 4000 MHz.
+ */
+#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
+
+/* defined rate in 500kbps */
+#define WLC_MAXRATE 108 /* in 500kbps units */
+#define WLC_RATE_1M 2 /* in 500kbps units */
+#define WLC_RATE_2M 4 /* in 500kbps units */
+#define WLC_RATE_5M5 11 /* in 500kbps units */
+#define WLC_RATE_11M 22 /* in 500kbps units */
+#define WLC_RATE_6M 12 /* in 500kbps units */
+#define WLC_RATE_9M 18 /* in 500kbps units */
+#define WLC_RATE_12M 24 /* in 500kbps units */
+#define WLC_RATE_18M 36 /* in 500kbps units */
+#define WLC_RATE_24M 48 /* in 500kbps units */
+#define WLC_RATE_36M 72 /* in 500kbps units */
+#define WLC_RATE_48M 96 /* in 500kbps units */
+#define WLC_RATE_54M 108 /* in 500kbps units */
+
+#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */
+
+/**
+ * Convert chanspec to ascii string
+ *
+ * @param chspec chanspec format
+ * @param buf ascii string of chanspec
+ *
+ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
+ *
+ * @see CHANSPEC_STR_LEN
+ */
extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf);
-
+/**
+ * Convert ascii string to chanspec
+ *
+ * @param a pointer to input string
+ *
+ * @return >= 0 if successful or 0 otherwise
+ */
extern chanspec_t wf_chspec_aton(const char *a);
-
+/**
+ * Verify the chanspec fields are valid.
+ *
+ * Verify the chanspec is using a legal set field values, i.e. that the chanspec
+ * specified a band, bw, ctl_sb and channel and that the combination could be
+ * legal given some set of circumstances.
+ *
+ * @param chanspec input chanspec to verify
+ *
+ * @return TRUE if the chanspec is malformed, FALSE if it looks good.
+ */
extern bool wf_chspec_malformed(chanspec_t chanspec);
-
+/**
+ * Verify the chanspec specifies a valid channel according to 802.11.
+ *
+ * @param chanspec input chanspec to verify
+ *
+ * @return TRUE if the chanspec is a valid 802.11 channel
+ */
extern bool wf_chspec_valid(chanspec_t chanspec);
-
+/**
+ * Return the primary (control) channel.
+ *
+ * This function returns the channel number of the primary 20MHz channel. For
+ * 20MHz channels this is just the channel number. For 40MHz or wider channels
+ * it is the primary 20MHz channel specified by the chanspec.
+ *
+ * @param chspec input chanspec
+ *
+ * @return Returns the channel number of the primary 20MHz channel
+ */
extern uint8 wf_chspec_ctlchan(chanspec_t chspec);
-
+/**
+ * Return the primary (control) chanspec.
+ *
+ * This function returns the chanspec of the primary 20MHz channel. For 20MHz
+ * channels this is just the chanspec. For 40MHz or wider channels it is the
+ * chanspec of the primary 20MHZ channel specified by the chanspec.
+ *
+ * @param chspec input chanspec
+ *
+ * @return Returns the chanspec of the primary 20MHz channel
+ */
extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec);
-
+/**
+ * Return a channel number corresponding to a frequency.
+ *
+ * This function returns the chanspec for the primary 40MHz of an 80MHz channel.
+ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using
+ * as the primary 20MHz channel.
+ */
extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec);
-
+/*
+ * Return the channel number for a given frequency and base frequency.
+ * The returned channel number is relative to the given base frequency.
+ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
+ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
+ *
+ * Frequency is specified in MHz.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
+ * 2.4 GHz and 5 GHz bands.
+ *
+ * The returned channel will be in the range [1, 14] in the 2.4 GHz band
+ * and [0, 200] otherwise.
+ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
+ * frequency is not a 2.4 GHz channel, or if the frequency is not and even
+ * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ *
+ * @param freq frequency in MHz
+ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
+ *
+ * @return Returns a channel number
+ *
+ * @see WF_CHAN_FACTOR_2_4_G
+ * @see WF_CHAN_FACTOR_5_G
+ */
extern int wf_mhz2channel(uint freq, uint start_factor);
-
+/**
+ * Return the center frequency in MHz of the given channel and base frequency.
+ *
+ * Return the center frequency in MHz of the given channel and base frequency.
+ * The channel number is interpreted relative to the given base frequency.
+ *
+ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
+ * 2.4 GHz and 5 GHz bands.
+ * The channel range of [1, 14] is only checked for a start_factor of
+ * WF_CHAN_FACTOR_2_4_G (4814).
+ * Odd start_factors produce channels on .5 MHz boundaries, in which case
+ * the answer is rounded down to an integral MHz.
+ * -1 is returned for an out of range channel.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ *
+ * @param channel input channel number
+ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
+ *
+ * @return Returns a frequency in MHz
+ *
+ * @see WF_CHAN_FACTOR_2_4_G
+ * @see WF_CHAN_FACTOR_5_G
+ */
extern int wf_channel2mhz(uint channel, uint start_factor);
-#endif
+/**
+ * Convert ctl chan and bw to chanspec
+ *
+ * @param ctl_ch channel
+ * @param bw bandwidth
+ *
+ * @return > 0 if successful or 0 otherwise
+ *
+ */
+extern uint16 wf_channel2chspec(uint ctl_ch, uint bw);
+
+#endif /* _bcmwifi_channels_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index dbfe2f7..acb2072 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -30,26 +30,26 @@
#define EPI_MINOR_VERSION 28
-#define EPI_RC_NUMBER 13
+#define EPI_RC_NUMBER 23
-#define EPI_INCREMENTAL_NUMBER 1
+#define EPI_INCREMENTAL_NUMBER 0
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 1, 28, 13, 1
+#define EPI_VERSION 1, 28, 23, 0
-#define EPI_VERSION_NUM 0x011c0d01
+#define EPI_VERSION_NUM 0x011c1700
-#define EPI_VERSION_DEV 1.28.13
+#define EPI_VERSION_DEV 1.28.23
/* Driver Version String, ASCII, 32 chars max */
#ifdef BCMINTERNAL
-#define EPI_VERSION_STR "1.28.13.1 (r BCMINT)"
+#define EPI_VERSION_STR "1.28.23 (r BCMINT)"
#else
#ifdef WLTEST
-#define EPI_VERSION_STR "1.28.13.1 (r WLTEST)"
+#define EPI_VERSION_STR "1.28.23 (r WLTEST)"
#else
-#define EPI_VERSION_STR "1.28.13.1 (r)"
+#define EPI_VERSION_STR "1.28.23 (r)"
#endif
#endif /* BCMINTERNAL */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
index 0a337f6..c439707 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -23,11 +23,14 @@
*
* Dependencies: proto/bcmeth.h
*
- * $Id: bcmevent.h 326276 2012-04-06 23:16:42Z $
+ * $Id: bcmevent.h 374275 2012-12-12 11:44:18Z $
*
*/
-
+/*
+ * Broadcom Ethernet Events protocol defines
+ *
+ */
#ifndef _BCMEVENT_H_
#define _BCMEVENT_H_
@@ -36,162 +39,169 @@
#include <typedefs.h>
#endif
-
+/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
-#define BCM_EVENT_MSG_VERSION 2
-#define BCM_MSG_IFNAME_MAX 16
-
-
-#define WLC_EVENT_MSG_LINK 0x01
-#define WLC_EVENT_MSG_FLUSHTXQ 0x02
-#define WLC_EVENT_MSG_GROUP 0x04
-#define WLC_EVENT_MSG_UNKBSS 0x08
-#define WLC_EVENT_MSG_UNKIF 0x10
-
+#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */
+#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */
+/* flags */
+#define WLC_EVENT_MSG_LINK 0x01 /* link is up */
+#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */
+#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */
+#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */
+#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */
+/* these fields are stored in network order */
+/* version 1 */
typedef BWL_PRE_PACKED_STRUCT struct
{
uint16 version;
- uint16 flags;
- uint32 event_type;
- uint32 status;
- uint32 reason;
- uint32 auth_type;
- uint32 datalen;
- struct ether_addr addr;
- char ifname[BCM_MSG_IFNAME_MAX];
+ uint16 flags; /* see flags below */
+ uint32 event_type; /* Message (see below) */
+ uint32 status; /* Status code (see below) */
+ uint32 reason; /* Reason code (if applicable) */
+ uint32 auth_type; /* WLC_E_AUTH */
+ uint32 datalen; /* data buf */
+ struct ether_addr addr; /* Station address (if applicable) */
+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */
} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t;
-
+/* the current version */
typedef BWL_PRE_PACKED_STRUCT struct
{
uint16 version;
- uint16 flags;
- uint32 event_type;
- uint32 status;
- uint32 reason;
- uint32 auth_type;
- uint32 datalen;
- struct ether_addr addr;
- char ifname[BCM_MSG_IFNAME_MAX];
- uint8 ifidx;
- uint8 bsscfgidx;
+ uint16 flags; /* see flags below */
+ uint32 event_type; /* Message (see below) */
+ uint32 status; /* Status code (see below) */
+ uint32 reason; /* Reason code (if applicable) */
+ uint32 auth_type; /* WLC_E_AUTH */
+ uint32 datalen; /* data buf */
+ struct ether_addr addr; /* Station address (if applicable) */
+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */
+ uint8 ifidx; /* destination OS i/f index */
+ uint8 bsscfgidx; /* source bsscfg index */
} BWL_POST_PACKED_STRUCT wl_event_msg_t;
-
+/* used by driver msgs */
typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
struct ether_header eth;
bcmeth_hdr_t bcm_hdr;
wl_event_msg_t event;
-
+ /* data portion follows */
} BWL_POST_PACKED_STRUCT bcm_event_t;
#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header))
-
-#define WLC_E_SET_SSID 0
-#define WLC_E_JOIN 1
-#define WLC_E_START 2
-#define WLC_E_AUTH 3
-#define WLC_E_AUTH_IND 4
-#define WLC_E_DEAUTH 5
-#define WLC_E_DEAUTH_IND 6
-#define WLC_E_ASSOC 7
-#define WLC_E_ASSOC_IND 8
-#define WLC_E_REASSOC 9
-#define WLC_E_REASSOC_IND 10
-#define WLC_E_DISASSOC 11
-#define WLC_E_DISASSOC_IND 12
-#define WLC_E_QUIET_START 13
-#define WLC_E_QUIET_END 14
-#define WLC_E_BEACON_RX 15
-#define WLC_E_LINK 16
-#define WLC_E_MIC_ERROR 17
-#define WLC_E_NDIS_LINK 18
-#define WLC_E_ROAM 19
-#define WLC_E_TXFAIL 20
-#define WLC_E_PMKID_CACHE 21
-#define WLC_E_RETROGRADE_TSF 22
-#define WLC_E_PRUNE 23
-#define WLC_E_AUTOAUTH 24
-#define WLC_E_EAPOL_MSG 25
-#define WLC_E_SCAN_COMPLETE 26
-#define WLC_E_ADDTS_IND 27
-#define WLC_E_DELTS_IND 28
-#define WLC_E_BCNSENT_IND 29
-#define WLC_E_BCNRX_MSG 30
-#define WLC_E_BCNLOST_MSG 31
-#define WLC_E_ROAM_PREP 32
-#define WLC_E_PFN_NET_FOUND 33
-#define WLC_E_PFN_NET_LOST 34
+/* Event messages */
+#define WLC_E_SET_SSID 0 /* indicates status of set SSID */
+#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */
+#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */
+#define WLC_E_AUTH 3 /* 802.11 AUTH request */
+#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */
+#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */
+#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */
+#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */
+#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */
+#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */
+#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */
+#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */
+#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */
+#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */
+#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */
+#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */
+#define WLC_E_LINK 16 /* generic link indication */
+#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */
+#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */
+#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */
+#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */
+#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */
+#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */
+#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */
+#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */
+#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */
+#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */
+#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */
+#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */
+#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */
+#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */
+#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */
+#define WLC_E_ROAM_PREP 32 /* before attempting to roam */
+#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */
+#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */
#define WLC_E_RESET_COMPLETE 35
#define WLC_E_JOIN_START 36
#define WLC_E_ROAM_START 37
#define WLC_E_ASSOC_START 38
#define WLC_E_IBSS_ASSOC 39
#define WLC_E_RADIO 40
-#define WLC_E_PSM_WATCHDOG 41
-#define WLC_E_PROBREQ_MSG 44
+#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */
+#define WLC_E_PROBREQ_MSG 44 /* probe request received */
#define WLC_E_SCAN_CONFIRM_IND 45
-#define WLC_E_PSK_SUP 46
+#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */
#define WLC_E_COUNTRY_CODE_CHANGED 47
-#define WLC_E_EXCEEDED_MEDIUM_TIME 48
-#define WLC_E_ICV_ERROR 49
-#define WLC_E_UNICAST_DECODE_ERROR 50
-#define WLC_E_MULTICAST_DECODE_ERROR 51
+#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */
+#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */
+#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */
+#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */
#define WLC_E_TRACE 52
#ifdef WLBTAMP
-#define WLC_E_BTA_HCI_EVENT 53
+#define WLC_E_BTA_HCI_EVENT 53 /* BT-AMP HCI event */
#endif
-#define WLC_E_IF 54
-#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55
-#define WLC_E_RSSI 56
-#define WLC_E_PFN_SCAN_COMPLETE 57
+#define WLC_E_IF 54 /* I/F change (for dongle host notification) */
+#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */
+#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */
+#define WLC_E_PFN_SCAN_COMPLETE 57 /* PFN completed scan of network list */
#define WLC_E_EXTLOG_MSG 58
-#define WLC_E_ACTION_FRAME 59
-#define WLC_E_ACTION_FRAME_COMPLETE 60
-#define WLC_E_PRE_ASSOC_IND 61
-#define WLC_E_PRE_REASSOC_IND 62
+#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */
+#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */
+#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */
+#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */
#define WLC_E_CHANNEL_ADOPTED 63
-#define WLC_E_AP_STARTED 64
-#define WLC_E_DFS_AP_STOP 65
-#define WLC_E_DFS_AP_RESUME 66
-#define WLC_E_WAI_STA_EVENT 67
-#define WLC_E_WAI_MSG 68
-#define WLC_E_ESCAN_RESULT 69
-#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
-#define WLC_E_PROBRESP_MSG 71
-#define WLC_E_P2P_PROBREQ_MSG 72
+#define WLC_E_AP_STARTED 64 /* AP started */
+#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */
+#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */
+#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */
+#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */
+#define WLC_E_ESCAN_RESULT 69 /* escan result event */
+#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */
+#define WLC_E_PROBRESP_MSG 71 /* probe response received */
+#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */
#define WLC_E_DCS_REQUEST 73
-#define WLC_E_FIFO_CREDIT_MAP 74
-
-#define WLC_E_ACTION_FRAME_RX 75
-#define WLC_E_WAKE_EVENT 76
-#define WLC_E_RM_COMPLETE 77
-#define WLC_E_HTSFSYNC 78
-#define WLC_E_OVERLAY_REQ 79
-#define WLC_E_CSA_COMPLETE_IND 80
-#define WLC_E_EXCESS_PM_WAKE_EVENT 81
-#define WLC_E_PFN_SCAN_NONE 82
-#define WLC_E_PFN_SCAN_ALLGONE 83
+#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */
+
+#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH
+ * wl_event_rx_frame_data_t header
+ */
+#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */
+#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */
+#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */
+#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */
+#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */
+#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */
+#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */
+#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */
#define WLC_E_GTK_PLUMBED 84
-#define WLC_E_ASSOC_IND_NDIS 85
-#define WLC_E_REASSOC_IND_NDIS 86
+#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */
+#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */
#define WLC_E_ASSOC_REQ_IE 87
#define WLC_E_ASSOC_RESP_IE 88
-#define WLC_E_ASSOC_RECREATED 89
-#define WLC_E_ACTION_FRAME_RX_NDIS 90
-#define WLC_E_AUTH_REQ 91
-#define WLC_E_TDLS_PEER_EVENT 92
-#define WLC_E_SPEEDY_RECREATE_FAIL 93
-#define WLC_E_LAST 94
-
-
-
+#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */
+#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */
+#define WLC_E_AUTH_REQ 91 /* authentication request received */
+#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected or disconnected peer */
+#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */
+#define WLC_E_SERVICE_FOUND 102 /* desired service found */
+#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */
+#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */
+#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */
+#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */
+#define WLC_E_LAST 107 /* highest val + 1 for range checking */
+
+
+/* Table of event name strings for UIs and debugging dumps */
typedef struct {
uint event;
const char *name;
@@ -200,82 +210,85 @@ typedef struct {
extern const bcmevent_name_t bcmevent_names[];
extern const int bcmevent_names_size;
-
-#define WLC_E_STATUS_SUCCESS 0
-#define WLC_E_STATUS_FAIL 1
-#define WLC_E_STATUS_TIMEOUT 2
-#define WLC_E_STATUS_NO_NETWORKS 3
-#define WLC_E_STATUS_ABORT 4
-#define WLC_E_STATUS_NO_ACK 5
-#define WLC_E_STATUS_UNSOLICITED 6
-#define WLC_E_STATUS_ATTEMPT 7
-#define WLC_E_STATUS_PARTIAL 8
-#define WLC_E_STATUS_NEWSCAN 9
-#define WLC_E_STATUS_NEWASSOC 10
-#define WLC_E_STATUS_11HQUIET 11
-#define WLC_E_STATUS_SUPPRESS 12
-#define WLC_E_STATUS_NOCHANS 13
-#define WLC_E_STATUS_CS_ABORT 15
-#define WLC_E_STATUS_ERROR 16
-
-
-#define WLC_E_REASON_INITIAL_ASSOC 0
-#define WLC_E_REASON_LOW_RSSI 1
-#define WLC_E_REASON_DEAUTH 2
-#define WLC_E_REASON_DISASSOC 3
-#define WLC_E_REASON_BCNS_LOST 4
-#define WLC_E_REASON_MINTXRATE 9
-#define WLC_E_REASON_TXFAIL 10
-
-
-#define WLC_E_REASON_FAST_ROAM_FAILED 5
-#define WLC_E_REASON_DIRECTED_ROAM 6
-#define WLC_E_REASON_TSPEC_REJECTED 7
-#define WLC_E_REASON_BETTER_AP 8
-
-
-#define WLC_E_REASON_REQUESTED_ROAM 11
-
-
-#define WLC_E_PRUNE_ENCR_MISMATCH 1
-#define WLC_E_PRUNE_BCAST_BSSID 2
-#define WLC_E_PRUNE_MAC_DENY 3
-#define WLC_E_PRUNE_MAC_NA 4
-#define WLC_E_PRUNE_REG_PASSV 5
-#define WLC_E_PRUNE_SPCT_MGMT 6
-#define WLC_E_PRUNE_RADAR 7
-#define WLC_E_RSN_MISMATCH 8
-#define WLC_E_PRUNE_NO_COMMON_RATES 9
-#define WLC_E_PRUNE_BASIC_RATES 10
-#define WLC_E_PRUNE_CIPHER_NA 12
-#define WLC_E_PRUNE_KNOWN_STA 13
-#define WLC_E_PRUNE_WDS_PEER 15
-#define WLC_E_PRUNE_QBSS_LOAD 16
-#define WLC_E_PRUNE_HOME_AP 17
-
-
-#define WLC_E_SUP_OTHER 0
-#define WLC_E_SUP_DECRYPT_KEY_DATA 1
-#define WLC_E_SUP_BAD_UCAST_WEP128 2
-#define WLC_E_SUP_BAD_UCAST_WEP40 3
-#define WLC_E_SUP_UNSUP_KEY_LEN 4
-#define WLC_E_SUP_PW_KEY_CIPHER 5
-#define WLC_E_SUP_MSG3_TOO_MANY_IE 6
-#define WLC_E_SUP_MSG3_IE_MISMATCH 7
-#define WLC_E_SUP_NO_INSTALL_FLAG 8
-#define WLC_E_SUP_MSG3_NO_GTK 9
-#define WLC_E_SUP_GRP_KEY_CIPHER 10
-#define WLC_E_SUP_GRP_MSG1_NO_GTK 11
-#define WLC_E_SUP_GTK_DECRYPT_FAIL 12
-#define WLC_E_SUP_SEND_FAIL 13
-#define WLC_E_SUP_DEAUTH 14
-#define WLC_E_SUP_WPA_PSK_TMO 15
-
-
-
+/* Event status codes */
+#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */
+#define WLC_E_STATUS_FAIL 1 /* operation failed */
+#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */
+#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */
+#define WLC_E_STATUS_ABORT 4 /* operation was aborted */
+#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */
+#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */
+#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */
+#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */
+#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */
+#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */
+#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */
+#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */
+#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */
+#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */
+#define WLC_E_STATUS_ERROR 16 /* request failed due to error */
+
+/* roam reason codes */
+#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */
+#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */
+#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */
+#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */
+#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */
+#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */
+#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */
+
+/* Roam codes used primarily by CCX */
+#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */
+#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */
+#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */
+#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */
+
+
+#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition request by AP */
+
+/* prune reason codes */
+#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */
+#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */
+#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */
+#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */
+#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */
+#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */
+#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */
+#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */
+#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */
+#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */
+#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */
+#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */
+#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */
+#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */
+#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */
+
+/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */
+#define WLC_E_SUP_OTHER 0 /* Other reason */
+#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */
+#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */
+#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */
+#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */
+#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */
+#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */
+#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */
+#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */
+#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */
+#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */
+#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */
+#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */
+#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */
+#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */
+#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */
+
+/* Event data for events that include frames received over the air */
+/* WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data {
uint16 version;
- uint16 channel;
+ uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */
int32 rssi;
uint32 mactime;
uint32 rate;
@@ -283,47 +296,73 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data {
#define BCM_RX_FRAME_DATA_VERSION 1
-
+/* WLC_E_IF event data */
typedef struct wl_event_data_if {
- uint8 ifidx;
- uint8 opcode;
+ uint8 ifidx; /* RTE virtual device index (for dongle) */
+ uint8 opcode; /* see I/F opcode */
uint8 reserved;
- uint8 bssidx;
- uint8 role;
+ uint8 bssidx; /* bsscfg index */
+ uint8 role; /* see I/F role */
} wl_event_data_if_t;
-
-#define WLC_E_IF_ADD 1
-#define WLC_E_IF_DEL 2
-#define WLC_E_IF_CHANGE 3
-
-
-#define WLC_E_IF_ROLE_STA 0
-#define WLC_E_IF_ROLE_AP 1
-#define WLC_E_IF_ROLE_WDS 2
-#define WLC_E_IF_ROLE_P2P_GO 3
-#define WLC_E_IF_ROLE_P2P_CLIENT 4
+/* opcode in WLC_E_IF event */
+#define WLC_E_IF_ADD 1 /* bsscfg add */
+#define WLC_E_IF_DEL 2 /* bsscfg delete */
+#define WLC_E_IF_CHANGE 3 /* bsscfg role change */
+
+/* I/F role code in WLC_E_IF event */
+#define WLC_E_IF_ROLE_STA 0 /* Infra STA */
+#define WLC_E_IF_ROLE_AP 1 /* Access Point */
+#define WLC_E_IF_ROLE_WDS 2 /* WDS link */
+#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */
+#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */
#ifdef WLBTAMP
-#define WLC_E_IF_ROLE_BTA_CREATOR 5
-#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6
+#define WLC_E_IF_ROLE_BTA_CREATOR 5 /* BT-AMP Creator */
+#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 /* BT-AMP Acceptor */
#endif
+/* Reason codes for LINK */
+#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */
+#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */
+#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */
+#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */
-#define WLC_E_LINK_BCN_LOSS 1
-#define WLC_E_LINK_DISASSOC 2
-#define WLC_E_LINK_ASSOC_REC 3
-#define WLC_E_LINK_BSSCFG_DIS 4
-
+/* reason codes for WLC_E_OVERLAY_REQ event */
+#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */
+#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */
-#define WLC_E_OVL_DOWNLOAD 0
-#define WLC_E_OVL_UPDATE_IND 1
-
-
-#define WLC_E_TDLS_PEER_DISCOVERED 0
+/* reason codes for WLC_E_TDLS_PEER_EVENT event */
+#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */
#define WLC_E_TDLS_PEER_CONNECTED 1
#define WLC_E_TDLS_PEER_DISCONNECTED 2
-
+/* GAS event data */
+typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas {
+ uint16 channel; /* channel of GAS protocol */
+ uint8 dialog_token; /* GAS dialog token */
+ uint8 fragment_id; /* fragment id */
+ uint16 status_code; /* status code on GAS completion */
+ uint16 data_len; /* length of data to follow */
+ uint8 data[1]; /* variable length specified by data_len */
+} BWL_POST_PACKED_STRUCT wl_event_gas_t;
+
+/* service discovery TLV */
+typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv {
+ uint16 length; /* length of response_data */
+ uint8 protocol; /* service protocol type */
+ uint8 transaction_id; /* service transaction id */
+ uint8 status_code; /* status code */
+ uint8 data[1]; /* response data */
+} BWL_POST_PACKED_STRUCT wl_sd_tlv_t;
+
+/* service discovery event data */
+typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd {
+ uint16 channel; /* channel */
+ uint8 count; /* number of tlvs */
+ wl_sd_tlv_t tlv[1]; /* service discovery TLV */
+} BWL_POST_PACKED_STRUCT wl_event_sd_t;
+
+/* This marks the end of a packed structure section. */
#include <packed_section_end.h>
-#endif
+#endif /* _BCMEVENT_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
index 1c8cc01..6b421b5 100644
--- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
+++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
@@ -18,7 +18,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* 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: wlfc_proto.h 347585 2012-07-27 09:02:53Z $
+* $Id: wlfc_proto.h 361006 2012-10-05 07:45:51Z $
*
*/
#ifndef __wlfc_proto_definitions_h__
@@ -97,6 +97,7 @@
#define WLFC_CTL_TYPE_NIC_PRD_END 16
#define WLFC_CTL_TYPE_AF_TXS 17
#define WLFC_CTL_TYPE_TRANS_ID 18
+#define WLFC_CTL_TYPE_COMP_TXSTATUS 19
#define WLFC_CTL_TYPE_FILLER 255
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index a93e8e8..c8c1995 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -24,7 +24,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: wlioctl.h 357627 2012-09-19 12:42:22Z $
+ * $Id: wlioctl.h 366141 2012-11-01 01:55:06Z $
*/
#ifndef _wlioctl_h_
@@ -503,6 +503,10 @@ typedef struct wl_uint32_list {
/* used for association with a specific BSSID and chanspec list */
typedef struct wl_assoc_params {
struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */
+ uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid,
+ * otherwise count of chanspecs in chanspec_list
+ * AND paired bssids following chanspec_list
+ */
int32 chanspec_num; /* 0: all available channels,
* otherwise count of chanspecs in chanspec_list
*/
@@ -843,7 +847,14 @@ typedef enum sup_auth_status {
#define CRYPTO_ALGO_AES_CCM 4
#define CRYPTO_ALGO_AES_OCB_MSDU 5
#define CRYPTO_ALGO_AES_OCB_MPDU 6
+#if !defined(BCMEXTCCX)
#define CRYPTO_ALGO_NALG 7
+#else
+#define CRYPTO_ALGO_CKIP 7
+#define CRYPTO_ALGO_CKIP_MMH 8
+#define CRYPTO_ALGO_WEP_MMH 9
+#define CRYPTO_ALGO_NALG 10
+#endif
#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */
#define WSEC_GEN_MIC_ERROR 0x0001
@@ -855,8 +866,13 @@ typedef enum sup_auth_status {
#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */
#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */
+#if defined(BCMEXTCCX)
+#define WL_CKIP_KP (1 << 4) /* CMIC */
+#define WL_CKIP_MMH (1 << 5) /* CKIP */
+#else
#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */
#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */
+#endif
#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */
typedef struct wl_wsec_key {
@@ -918,6 +934,10 @@ typedef struct {
#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */
#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */
#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */
+#if defined(BCMEXTCCX)
+#define WPA_AUTH_CCKM 0x0008 /* CCKM */
+#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */
+#endif
/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */
#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */
#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */
@@ -1896,6 +1916,12 @@ typedef struct wl_po {
#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */
#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */
+/* AP environment */
+#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */
+#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */
+#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */
+#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */
+
typedef struct wl_aci_args {
int enter_aci_thresh; /* Trigger level to start detecting ACI */
int exit_aci_thresh; /* Trigger level to exit ACI mode */
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
index d03a095..93990d9 100644
--- a/drivers/net/wireless/bcmdhd/linux_osl.c
+++ b/drivers/net/wireless/bcmdhd/linux_osl.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: linux_osl.c 355147 2012-09-05 15:03:49Z $
+ * $Id: linux_osl.c 373382 2012-12-07 07:59:52Z $
*/
#define LINUX_PORT
@@ -35,17 +35,13 @@
#include <linux/delay.h>
#include <pcicfg.h>
-#ifdef BCMASSERT_LOG
-#include <bcm_assert_log.h>
-#endif
-
#include <linux/fs.h>
#define PCI_CFG_RETRY 10
-#define OS_HANDLE_MAGIC 0x1234abcd
-#define BCM_MEM_FILENAME_LEN 24
+#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */
+#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
#ifdef CONFIG_DHD_USE_STATIC_BUF
#define DHD_SKB_HDRSIZE 336
@@ -1013,19 +1009,17 @@ osl_assert(const char *exp, const char *file, int line)
const char *basename;
basename = strrchr(file, '/');
-
+ /* skip the '/' */
if (basename)
basename++;
if (!basename)
basename = file;
-#ifdef BCMASSERT_LOG
snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n",
exp, basename, line);
- bcm_assert_log(tempbuf);
-#endif
+ printk("%s", tempbuf);
}
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 4dd024b..a76ba53 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.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_android.c 358186 2012-09-21 14:36:14Z $
+ * $Id: wl_android.c 372668 2012-12-04 14:07:12Z $
*/
#include <linux/module.h>
@@ -590,7 +590,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
#ifdef WL_CFG80211
else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
char *country_code = command + strlen(CMD_COUNTRY) + 1;
- bytes_written = wldev_set_country(net, country_code);
+ bytes_written = wldev_set_country(net, country_code, true);
}
#endif /* WL_CFG80211 */
#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 4c988e7..0cbf60c 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/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 359682 2012-09-28 20:23:14Z $
+ * $Id: wl_cfg80211.c 374275 2012-12-12 11:44:18Z $
*/
#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
#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
@@ -100,6 +105,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).
@@ -322,12 +331,19 @@ static u32 wl_get_ielen(struct wl_priv *wl);
static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev);
static void wl_free_wdev(struct wl_priv *wl);
+static int
+wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
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_cfg80211_40MHz_to_20MHz_Channel(chanspec_t chspec);
+s32 wl_cfg80211_channel_to_freq(u32 channel);
+
+#if defined(DHCP_SCAN_SUPPRESS)
+static void wl_cfg80211_work_handler(struct work_struct *work);
+static void wl_cfg80211_scan_supp_timerfunc(ulong data);
+#endif /* DHCP_SCAN_SUPPRESS */
static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr,
@@ -872,37 +888,6 @@ wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */
-static s32
-wl_cfg80211_40MHz_to_20MHz_Channel(chanspec_t chspec)
-{
- u32 channel = chspec & WL_CHANSPEC_CHAN_MASK;
-
- /* If chspec is not for 40MHz. Do nothing */
- if (!(chspec & WL_CHANSPEC_BW_40))
- return channel;
-
- if ((channel < 0) || (channel > MAXCHANNEL))
- return -1;
-
- switch (channel) {
- /* 5G Channels */
- case 38:
- case 46:
- case 151:
- case 159:
- if (chspec & WL_CHANSPEC_CTL_SB_LOWER)
- channel = channel - CH_10MHZ_APART;
- else if (chspec & WL_CHANSPEC_CTL_SB_UPPER)
- channel = channel + CH_10MHZ_APART;
- break;
- default:
- /* Mhz adjustment not required. Use as is */
- WL_ERR(("Unsupported channel: %d \n", channel));
- }
-
- return channel;
-}
-
static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
{
chanspec_t chspec;
@@ -931,11 +916,6 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
else {
bss = (struct wl_bss_info *) (wl->extra_buf + 4);
chspec = bss->chanspec;
- if (chspec & WL_CHANSPEC_BW_40) {
- uint32 channel = wl_cfg80211_40MHz_to_20MHz_Channel(chspec);
- chspec = wl_ch_host_to_driver(channel);
- }
-
WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
}
return chspec;
@@ -1057,7 +1037,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
if (!dhd)
return ERR_PTR(-ENODEV);
#endif /* PROP_TXSTATUS_VSDB */
- if (!wl->p2p || !wl->p2p->vir_ifname)
+ if (!wl->p2p)
return ERR_PTR(-ENODEV);
if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
@@ -1230,6 +1210,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
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
@@ -1243,7 +1224,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
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,
@@ -1425,10 +1406,9 @@ wl_cfg80211_ifdel_ops(struct net_device *ndev)
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_VSDB
if (dhd->wlfc_enabled && wl->wlfc_on) {
@@ -1796,6 +1776,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
}
wl_scan_prep(&params->params, request);
+
params->version = htod32(ESCAN_REQ_VERSION);
params->action = htod16(action);
params->sync_id = htod16(0x1234);
@@ -1807,8 +1788,13 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
}
err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
- if (unlikely(err))
- WL_ERR((" Escan set error (%d)\n", err));
+ if (unlikely(err)) {
+ if (err == BCME_EPERM)
+ /* Scan Not permitted at this point of time */
+ WL_DBG((" Escan not permitted at this time (%d)\n", err));
+ else
+ WL_ERR((" Escan set error (%d)\n", err));
+ }
kfree(params);
}
else if (p2p_is_on(wl) && p2p_scan(wl)) {
@@ -1888,7 +1874,11 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
}
exit:
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ /* Don't print Error incase of Scan suppress */
+ if ((err == BCME_EPERM) && wl->scan_suppressed)
+ WL_DBG(("Escan failed: Scan Suppressed \n"));
+ else
+ WL_ERR(("error (%d)\n", err));
}
return err;
}
@@ -2180,7 +2170,10 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
- WL_ERR(("scan error (%d)\n", err));
+ if ((err == BCME_EPERM) && wl->scan_suppressed)
+ WL_DBG(("scan not permitted at this time (%d)\n", err));
+ else
+ WL_ERR(("scan error (%d)\n", err));
return err;
}
@@ -2795,6 +2788,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
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
@@ -3436,7 +3430,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
s32 err = 0;
struct wl_priv *wl = wiphy_priv(wiphy);
struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev);
-#ifndef SUPPORT_PM2_ONLY
+#if !defined(SUPPORT_PM2_ONLY)
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
#endif
@@ -3445,21 +3439,23 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
if (wl->p2p_net == dev || _net_info == NULL) {
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 */
-#ifndef SUPPORT_PM2_ONLY
pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF;
#else
pm = enabled ? PM_FAST : PM_OFF;
-#endif
+#endif /* SUPPORT_PM2_ONLY */
- /* 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"));
+ /* 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)
@@ -3748,6 +3744,13 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
} 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);
@@ -4070,6 +4073,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
#ifdef VSDB
ulong off_chan_started_jiffies = 0;
#endif
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len);
@@ -4100,7 +4104,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
} 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;
@@ -4110,7 +4114,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
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 {
@@ -4125,6 +4129,10 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
} else {
WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
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 */
@@ -4461,11 +4469,16 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
enum nl80211_channel_type channel_type)
{
s32 _chan;
-#ifdef HT40_GO
- s32 center_chan;
chanspec_t chspec = 0;
-#endif
+ chanspec_t fw_chspec = 0;
+ u32 bw = WL_CHANSPEC_BW_20;
+
s32 err = BCME_OK;
+ s32 bw_cap = 0;
+ struct {
+ u32 band;
+ u32 bw_cap;
+ } param = {0, 0};
struct wl_priv *wl = wiphy_priv(wiphy);
if (wl->p2p_net == dev) {
@@ -4475,45 +4488,70 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
dev->ifindex, channel_type, _chan));
-#ifdef HT40_GO
- switch (_chan) {
- /* adjust channel to center of 40MHz band */
- case 40:
- case 48:
- case 153:
- case 161:
- if (_chan <= (MAXCHANNEL - CH_20MHZ_APART))
- center_chan = _chan - CH_10MHZ_APART;
- chspec = CH40MHZ_CHSPEC(center_chan, WL_CHANSPEC_CTL_SB_UPPER);
- break;
- case 36:
- case 44:
- case 149:
- case 157:
- if (_chan <= (MAXCHANNEL - CH_20MHZ_APART))
- center_chan = _chan + CH_10MHZ_APART;
- chspec = CH40MHZ_CHSPEC(center_chan, WL_CHANSPEC_CTL_SB_LOWER);
- break;
- default:
- chspec = CH20MHZ_CHSPEC(_chan);
- break;
- }
- chspec = wl_chspec_host_to_driver(chspec);
- if ((err = wldev_iovar_setint(dev, "chanspec", chspec)) == BCME_BADCHAN) {
- err = wldev_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), true);
- if (err < 0) {
- WL_ERR(("WLC_SET_CHANNEL error %d"
- "chip may not be supporting this channel\n", err));
+ if (chan->band == IEEE80211_BAND_5GHZ) {
+ param.band = WLC_BAND_5G;
+ err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+ wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync);
+ if (err) {
+ if (err != BCME_UNSUPPORTED) {
+ WL_ERR(("bw_cap failed, %d\n", err));
+ return err;
+ } else {
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+ if (err) {
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
+ }
+ if (bw_cap != WLC_N_BW_20ALL)
+ bw = WL_CHANSPEC_BW_40;
+ }
+ } else {
+ if (WL_BW_CAP_80MHZ(wl->ioctl_buf[0]))
+ bw = WL_CHANSPEC_BW_80;
+ else if (WL_BW_CAP_40MHZ(wl->ioctl_buf[0]))
+ bw = WL_CHANSPEC_BW_40;
+ else
+ bw = WL_CHANSPEC_BW_20;
+
}
+
+ } else if (chan->band == IEEE80211_BAND_2GHZ)
+ bw = WL_CHANSPEC_BW_20;
+set_channel:
+ chspec = wf_channel2chspec(_chan, bw);
+ if (wf_chspec_valid(chspec)) {
+ fw_chspec = wl_chspec_host_to_driver(chspec);
+ if (fw_chspec != INVCHANSPEC) {
+ if ((err = wldev_iovar_setint(dev, "chanspec",
+ fw_chspec)) == BCME_BADCHAN) {
+ if (bw == WL_CHANSPEC_BW_80)
+ goto change_bw;
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &_chan, sizeof(_chan), true);
+ if (err < 0) {
+ WL_ERR(("WLC_SET_CHANNEL error %d"
+ "chip may not be supporting this channel\n", err));
+ }
+ } else if (err) {
+ WL_ERR(("failed to set chanspec error %d\n", err));
+ }
+ } else {
+ WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
+ err = BCME_ERROR;
+ }
+ } else {
+change_bw:
+ if (bw == WL_CHANSPEC_BW_80)
+ bw = WL_CHANSPEC_BW_40;
+ else if (bw == WL_CHANSPEC_BW_40)
+ bw = WL_CHANSPEC_BW_20;
+ else
+ bw = 0;
+ if (bw)
+ goto set_channel;
+ WL_ERR(("Invalid chanspec 0x%x\n", chspec));
+ err = BCME_ERROR;
}
-#else
- err = wldev_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), true);
- if (err < 0) {
- WL_ERR(("WLC_SET_CHANNEL error %d"
- "chip may not be supporting this channel\n", err));
- }
-#endif /* HT40_GO */
return err;
}
@@ -5692,6 +5730,37 @@ s32 wl_mode_to_nl80211_iftype(s32 mode)
return err;
}
+static int
+wl_cfg80211_reg_notifier(
+ struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy);
+ int ret = 0;
+
+ if (!request || !wl) {
+ WL_ERR(("Invalid arg\n"));
+ return -EINVAL;
+ }
+
+ WL_DBG(("ccode: %c%c Initiator: %d\n",
+ request->alpha2[0], request->alpha2[1], request->initiator));
+
+ /* We support only REGDOM_SET_BY_USER as of now */
+ if (request->initiator != NL80211_REGDOM_SET_BY_USER) {
+ WL_ERR(("reg_notifier for intiator:%d not supported \n",
+ request->initiator));
+ return -ENOTSUPP;
+ }
+
+ if ((ret = wldev_set_country(wl_to_prmry_ndev(wl), request->alpha2,
+ false)) < 0) {
+ WL_ERR(("set country Failed :%d\n", ret));
+ }
+
+ return ret;
+}
+
static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev)
{
s32 err = 0;
@@ -5760,6 +5829,9 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
*/
wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
#endif
+
+ wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
+
WL_DBG(("Registering custom regulatory)\n"));
wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
@@ -5802,14 +5874,14 @@ static s32 wl_inform_bss(struct wl_priv *wl)
WL_DBG(("scanned AP count (%d)\n", bss_list->count));
bi = next_bss(bss_list, bi);
for_each_bss(bss_list, bi, i) {
- err = wl_inform_single_bss(wl, bi);
+ err = wl_inform_single_bss(wl, bi, 0);
if (unlikely(err))
break;
}
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;
@@ -5824,6 +5896,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
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"));
@@ -5864,7 +5937,36 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
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,
@@ -6015,13 +6117,13 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
/* 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 */
@@ -6411,7 +6513,7 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
}
}
-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;
@@ -6459,7 +6561,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
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);
+ err = wl_inform_single_bss(wl, bi, is_roam_done);
if (unlikely(err))
goto update_bss_info_out;
@@ -6510,7 +6612,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
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",
MAC2STRDBG((u8*)(&e->addr)));
@@ -6570,7 +6672,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
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);
}
@@ -6672,7 +6774,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
memset(bss_list, 0, len);
bss_list->buflen = htod32(len);
err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
- if (unlikely(err)) {
+ if (unlikely(err) && unlikely(!wl->scan_suppressed)) {
WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
err = -EINVAL;
goto scan_done_out;
@@ -7848,152 +7950,161 @@ 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)
+{
+ 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;
+}
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) {
+ pm = PM_OFF;
+ WL_DBG(("%s:AP power save %s\n", _net_info->ndev->name,
+ pm ? "enabled" : "disabled"));
+ if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM,
+ &pm, sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:net_device is not ready\n",
+ _net_info->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n", _net_info->ndev->name, err));
}
- for_each_ndev(wl, iter, next) {
- if ((connected_cnt == 1) && (iter->ndev != _net_info->ndev))
- 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;
- } else {
- wl_cfg80211_update_power_mode(iter->ndev);
- }
- }
- 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));
- }
- }
- }
+ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
+ WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
+ return 0;
+ }
+ wl_cfg80211_determine_vsdb_mode(wl);
+ pm = PM_OFF;
+ for_each_ndev(wl, iter, next) {
+ if ((!wl->vsdb_mode) && (iter->ndev != _net_info->ndev)) {
+ /* Do not touch the other interfaces power save
+ * if we are not in vsdb mode
+ */
+ continue;
}
- 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"));
+ /* Save the current power mode */
+ iter->pm_restore = true;
+ 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 = 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 = pm ? true: false;
}
- 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;
- } else {
- wl_cfg80211_update_power_mode(iter->ndev);
- }
- }
- }
- }
- 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) {
+ 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;
}
- break;
- }
- default:
- break;
}
+ wl_cfg80211_concurrent_roam(wl, 0);
}
return err;
}
@@ -8063,6 +8174,7 @@ static s32 wl_init_priv(struct wl_priv *wl)
return -ENOMEM;
wl_init_event_handler(wl);
mutex_init(&wl->usr_sync);
+ mutex_init(&wl->event_sync);
err = wl_init_scan(wl);
if (err)
return err;
@@ -8262,8 +8374,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)
@@ -8509,14 +8622,79 @@ static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 ift
return 0;
}
-s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
{
+ if (!ev || (event > WLC_E_LAST))
+ return;
+
+ if (ev->num < MAX_EVENT_BUF_NUM) {
+ ev->event[ev->num].type = event;
+ ev->event[ev->num].set = set;
+ ev->num++;
+ } else {
+ WL_ERR(("evenbuffer doesn't support > %u events. Update"
+ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
+ ASSERT(0);
+ }
+}
+
+s32 wl_cfg80211_apply_eventbuffer(
+ struct net_device *ndev,
+ struct wl_priv *wl,
+ wl_eventmsg_buf_t *ev)
+{
+ char eventmask[WL_EVENTING_MASK_LEN];
+ int i, ret = 0;
s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+ if (!ev || (!ev->num))
+ return -EINVAL;
+
+ mutex_lock(&wl->event_sync);
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
+ sizeof(iovbuf));
+ ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(ret)) {
+ WL_ERR(("Get event_msgs error (%d)\n", ret));
+ goto exit;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+
+ /* apply the set bits */
+ for (i = 0; i < ev->num; i++) {
+ if (ev->event[i].set)
+ setbit(eventmask, ev->event[i].type);
+ else
+ clrbit(eventmask, ev->event[i].type);
+ }
+
+ /* Write updated Event mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ if (unlikely(ret)) {
+ WL_ERR(("Set event_msgs error (%d)\n", ret));
+ }
+
+exit:
+ mutex_unlock(&wl->event_sync);
+ return ret;
+}
+
+s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+{
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
s8 eventmask[WL_EVENTING_MASK_LEN];
s32 err = 0;
- if (!ndev)
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ if (!ndev || !wl)
return -ENODEV;
+
+ mutex_lock(&wl->event_sync);
+
/* Setup event_msgs */
bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
sizeof(iovbuf));
@@ -8540,8 +8718,8 @@ s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
}
eventmsg_out:
+ mutex_unlock(&wl->event_sync);
return err;
-
}
static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
@@ -8591,14 +8769,18 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
channel += CH_10MHZ_APART;
else
channel -= CH_10MHZ_APART;
+ } else if (CHSPEC_IS80(c)) {
+ WL_DBG(("HT80 center channel : %d\n", channel));
+ continue;
}
- 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;
@@ -8608,6 +8790,8 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
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;
@@ -8677,7 +8861,7 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
return err;
}
-s32 wl_update_wiphybands(struct wl_priv *wl)
+s32 wl_update_wiphybands(struct wl_priv *wl, bool notify)
{
struct wiphy *wiphy;
struct net_device *dev;
@@ -8690,6 +8874,7 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
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;
@@ -8705,6 +8890,7 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
WL_ERR(("error read bandlist (%d)\n", err));
goto end_bands;
}
+
wiphy = wl_to_wiphy(wl);
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
@@ -8720,10 +8906,10 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
if (unlikely(err)) {
WL_ERR(("error reading nmode (%d)\n", err));
} else {
- /* For nmodeonly check bw cap */
+ /* For nmodeonly check bw cap */
err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
if (unlikely(err)) {
- WL_ERR(("error get mimo_bw_cap (%d)\n", err));
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
}
}
@@ -8737,36 +8923,42 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
}
nband = bandlist[0];
+
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;
+ 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;
+ 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 */
- wiphy->bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
}
}
- wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
+ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
+
+ if (notify)
+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
+
end_bands:
if (rollback_lock)
mutex_unlock(&wl->usr_sync);
@@ -8789,7 +8981,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl)
if (unlikely(err && err != -EINPROGRESS)) {
WL_ERR(("wl_config_ifmode failed\n"));
}
- err = wl_update_wiphybands(wl);
+ err = wl_update_wiphybands(wl, true);
if (unlikely(err)) {
WL_ERR(("wl_update_wiphybands failed\n"));
}
@@ -8805,6 +8997,14 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl)
}
#endif /* WL_HOST_BAND_MGMT */
+#if defined(DHCP_SCAN_SUPPRESS)
+ /* wlan scan_supp timer and work thread info */
+ init_timer(&wl->scan_supp_timer);
+ wl->scan_supp_timer.data = (ulong)wl;
+ wl->scan_supp_timer.function = wl_cfg80211_scan_supp_timerfunc;
+ INIT_WORK(&wl->wlan_work, wl_cfg80211_work_handler);
+#endif /* DHCP_SCAN_SUPPRESS */
+
wl_set_drv_status(wl, READY, ndev);
return err;
}
@@ -8816,7 +9016,24 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
struct net_info *iter, *next;
struct net_device *ndev = wl_to_prmry_ndev(wl);
struct net_device *p2p_net = wl->p2p_net;
+ u32 bssidx = wl_cfgp2p_find_idx(wl, ndev);
WL_DBG(("In\n"));
+
+#if defined(DHCP_SCAN_SUPPRESS)
+ /* Force clear of scan_suppress */
+ if (wl->scan_suppressed)
+ wl_cfg80211_scan_suppress(ndev, 0);
+ if (timer_pending(&wl->scan_supp_timer))
+ del_timer_sync(&wl->scan_supp_timer);
+ cancel_work_sync(&wl->wlan_work);
+#endif /* DHCP_SCAN_SUPPRESS */
+
+ /* If BSS is operational (e.g SoftAp), bring it down */
+ if (wl_cfgp2p_bss_isup(ndev, bssidx)) {
+ if (wl_cfgp2p_bss(wl, ndev, bssidx, 0) < 0)
+ WL_ERR(("BSS down failed \n"));
+ }
+
/* Check if cfg80211 interface is already down */
if (!wl_get_drv_status(wl, READY, ndev))
return err; /* it is even not ready */
@@ -8945,6 +9162,7 @@ static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item)
break;
case WL_PROF_SSID:
rptr = &profile->ssid;
+ break;
case WL_PROF_CHAN:
rptr = &profile->channel;
break;
@@ -9173,6 +9391,25 @@ s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
return wl_cfgp2p_set_p2p_ps(wl, net, buf, len);
}
+s32 wl_cfg80211_channel_to_freq(u32 channel)
+{
+ int freq = 0;
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+#else
+ {
+ u16 band = 0;
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = IEEE80211_BAND_2GHZ;
+ else
+ band = IEEE80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(channel, band);
+ }
+#endif
+ return freq;
+}
+
s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
enum wl_management_type type)
{
@@ -9345,3 +9582,97 @@ wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
return 0;
}
+
+#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 */
+
+#if defined(DHCP_SCAN_SUPPRESS)
+static void wl_cfg80211_scan_supp_timerfunc(ulong data)
+{
+ struct wl_priv *wl = (struct wl_priv *)data;
+
+ WL_DBG(("Enter \n"));
+ schedule_work(&wl->wlan_work);
+}
+
+static void wl_cfg80211_work_handler(struct work_struct *work)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ wl = container_of(work, struct wl_priv, wlan_work);
+
+ if (!wl) {
+ WL_ERR(("wl_priv ptr NULL\n"));
+ return;
+ }
+
+ if (wl->scan_suppressed) {
+ /* There is pending scan_suppress. Clean it */
+ WL_ERR(("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT));
+ wl_cfg80211_scan_suppress(wl_to_prmry_ndev(wl), 0);
+ }
+}
+
+int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+ int ret = 0;
+
+ if (!dev || !wl || ((suppress != 0) && (suppress != 1)))
+ return -EINVAL;
+
+ if (suppress == wl->scan_suppressed) {
+ WL_DBG(("No change in scan_suppress state. Ignoring cmd..\n"));
+ return 0;
+ }
+
+ if (timer_pending(&wl->scan_supp_timer))
+ del_timer_sync(&wl->scan_supp_timer);
+
+ if ((ret = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
+ &suppress, sizeof(int), true)) < 0) {
+ WL_ERR(("Scan suppress setting failed ret:%d \n", ret));
+ } else {
+ WL_DBG(("Scan suppress %s \n", suppress ? "Enabled" : "Disabled"));
+ wl->scan_suppressed = suppress;
+ }
+
+ /* If scan_suppress is set, Start a timer to monitor it (just incase) */
+ if (wl->scan_suppressed) {
+ if (ret) {
+ WL_ERR(("Retry scan_suppress reset at a later time \n"));
+ mod_timer(&wl->scan_supp_timer,
+ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_RETRY));
+ } else {
+ WL_DBG(("Start wlan_timer to clear of scan_suppress \n"));
+ mod_timer(&wl->scan_supp_timer,
+ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_TIMEOUT));
+ }
+ }
+
+ return ret;
+}
+#endif /* DHCP_SCAN_SUPPRESS */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index 3ee1033..aaab95b 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -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.h 358186 2012-09-21 14:36:14Z $
+ * $Id: wl_cfg80211.h 374275 2012-12-12 11:44:18Z $
*/
#ifndef _wl_cfg80211_h_
@@ -62,21 +62,23 @@ struct wl_ibss;
/* 0 invalidates all debug messages. default is 1 */
#define WL_DBG_LEVEL 0xFF
+#define CFG80211_ERROR_TEXT "CFG80211-ERROR) "
+
#if defined(DHD_DEBUG)
#define WL_ERR(args) \
do { \
if (wl_dbg_level & WL_DBG_ERR) { \
- printk(KERN_INFO "CFG80211-ERROR) %s : ", __func__); \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
printk args; \
- } \
+ } \
} while (0)
#else /* defined(DHD_DEBUG) */
#define WL_ERR(args) \
do { \
if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \
- printk(KERN_INFO "CFG80211-ERROR) %s : ", __func__); \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
printk args; \
- } \
+ } \
} while (0)
#endif /* defined(DHD_DEBUG) */
@@ -126,6 +128,7 @@ do { \
#define WL_DBG(args)
#endif /* (WL_DBG_LEVEL > 0) */
#define WL_PNO(x)
+#define WL_SD(x)
#define WL_SCAN_RETRY_MAX 3
@@ -162,6 +165,10 @@ do { \
#define WL_SCB_TIMEOUT 20
#endif
+/* SCAN_SUPPRESS timer values in ms */
+#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */
+#define WL_SCAN_SUPPRESS_RETRY 3000
+
/* driver status */
enum wl_status {
WL_STATUS_READY = 0,
@@ -333,7 +340,9 @@ struct net_info {
s32 mode;
s32 roam_off;
unsigned long sme_state;
+ bool pm_restore;
bool pm_block;
+ s32 pm;
struct list_head list; /* list of all net_info structure */
};
typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl);
@@ -457,6 +466,16 @@ struct parsed_ies {
u32 wpa2_ie_len;
};
+
+#define MAX_EVENT_BUF_NUM 16
+typedef struct wl_eventmsg_buf {
+ u16 num;
+ struct {
+ u16 type;
+ bool set;
+ } event [MAX_EVENT_BUF_NUM];
+} wl_eventmsg_buf_t;
+
/* private data of cfg80211 interface */
struct wl_priv {
struct wireless_dev *wdev; /* representing wl cfg80211 device */
@@ -552,6 +571,10 @@ struct wl_priv {
#ifdef WL_HOST_BAND_MGMT
u8 curr_band;
#endif /* WL_HOST_BAND_MGMT */
+ bool scan_suppressed;
+ struct timer_list scan_supp_timer;
+ struct work_struct wlan_work;
+ struct mutex event_sync; /* maily for up/down synchronization */
};
@@ -575,6 +598,8 @@ wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev,
_net_info->mode = mode;
_net_info->ndev = ndev;
_net_info->wdev = wdev;
+ _net_info->pm_restore = 0;
+ _net_info->pm = 0;
_net_info->pm_block = pm_block;
_net_info->roam_off = WL_INVALID;
wl->iface_cnt++;
@@ -809,11 +834,17 @@ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
extern s32 wl_mode_to_nl80211_iftype(s32 mode);
int wl_cfg80211_do_driver_init(struct net_device *net);
void wl_cfg80211_enable_trace(bool set, u32 level);
-extern s32 wl_update_wiphybands(struct wl_priv *wl);
+extern s32 wl_update_wiphybands(struct wl_priv *wl, bool notify);
extern s32 wl_cfg80211_if_is_group_owner(void);
extern chanspec_t wl_ch_host_to_driver(u16 channel);
extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
extern void wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev);
extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band);
extern int wl_cfg80211_update_power_mode(struct net_device *dev);
+#if defined(DHCP_SCAN_SUPPRESS)
+extern int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress);
+#endif
+extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set);
+extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev,
+ struct wl_priv *wl, wl_eventmsg_buf_t *ev);
#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index 2c0f022..6319146 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.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_cfgp2p.c 358702 2012-09-25 06:48:56Z $
+ * $Id: wl_cfgp2p.c 372668 2012-12-04 14:07:12Z $
*
*/
#include <typedefs.h>
@@ -621,7 +621,7 @@ wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
/* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
* have no discovery BSS.
*/
- wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = WL_INVALID;
wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
return ret;
@@ -1197,16 +1197,25 @@ exit:
s32
wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
{
+ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
+ VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
+ s32 index = -1;
+ struct net_device *ndev = wl_cfgp2p_find_ndev(wl, bssidx);
#define INIT_IE(IE_TYPE, BSS_TYPE) \
do { \
memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
} while (0);
- if (bssidx < 0) {
- CFGP2P_ERR(("invalid bssidx\n"));
+
+ if (bssidx < 0 || ndev == NULL) {
+ CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev"));
return BCME_BADARG;
}
+ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
+ /* clean up vndr ies in dongle */
+ wl_cfgp2p_set_management_ie(wl, ndev, bssidx, vndrie_flag[index], NULL, 0);
+ }
INIT_IE(probe_req, bssidx);
INIT_IE(probe_res, bssidx);
INIT_IE(assoc_req, bssidx);
@@ -1376,6 +1385,28 @@ wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
exit:
return index;
}
+
+struct net_device *
+wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx)
+{
+ u32 i;
+ struct net_device *ndev = NULL;
+ if (bssidx < 0) {
+ CFGP2P_ERR((" bsscfg idx is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) {
+ ndev = wl_to_p2p_bss_ndev(wl, i);
+ break;
+ }
+ }
+
+exit:
+ return ndev;
+}
+
/*
* Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
*/
@@ -1623,6 +1654,7 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
{
s32 ret = BCME_OK;
s32 timeout = 0;
+ wl_eventmsg_buf_t buf;
CFGP2P_INFO(("\n"));
@@ -1631,6 +1663,13 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
wl_clr_p2p_status(wl, ACTION_TX_COMPLETED);
wl_clr_p2p_status(wl, ACTION_TX_NOACK);
+
+ bzero(&buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true);
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true);
+ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0)
+ return ret;
+
#define MAX_WAIT_TIME 2000
if (bssidx == P2PAPI_BSSCFG_PRIMARY)
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
@@ -1644,7 +1683,6 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (ret < 0) {
-
CFGP2P_ERR((" sending action frame is failed\n"));
goto exit;
}
@@ -1664,6 +1702,13 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
exit:
CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
+
+ bzero(&buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false);
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false);
+ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0)
+ WL_ERR(("TX frame events revert back failed \n"));
+
#undef MAX_WAIT_TIME
return ret;
}
@@ -1820,17 +1865,23 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
}
return p2p_supported;
}
+
/* Cleanup P2P resources */
s32
wl_cfgp2p_down(struct wl_priv *wl)
{
-
+ s32 i = 0, index = -1;
wl_cfgp2p_cancel_listen(wl,
wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE);
-
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ index = wl_to_p2p_bss_bssidx(wl, i);
+ if (index != WL_INVALID)
+ wl_cfgp2p_clear_management_ie(wl, index);
+ }
wl_cfgp2p_deinit_priv(wl);
return 0;
}
+
s32
wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
{
@@ -1973,10 +2024,11 @@ wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int
}
if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) {
-#ifdef SUPPORT_PM2_ONLY
+#if !defined(SUPPORT_PM2_ONLY)
if (legacy_ps == PM_MAX)
legacy_ps = PM_FAST;
-#endif
+#endif /* SUPPORT_PM2_ONLY */
+
ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true);
if (unlikely(ret)) {
@@ -2103,13 +2155,25 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl)
{
int ret = 0;
struct net_device* net = NULL;
- struct wireless_dev *wdev;
+ struct wireless_dev *wdev = NULL;
uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
+ if (wl->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ }
+
/* Allocate etherdev, including space for private structure */
if (!(net = alloc_etherdev(sizeof(struct wl_priv *)))) {
CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
- goto fail;
+ return -ENODEV;
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ free_netdev(net);
+ return -ENOMEM;
}
strncpy(net->name, "p2p%d", sizeof(net->name) - 1);
@@ -2132,12 +2196,6 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl)
/* Register with a dummy MAC addr */
memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (unlikely(!wdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
- return -ENOMEM;
- }
-
wdev->wiphy = wl->wdev->wiphy;
wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
@@ -2153,40 +2211,23 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl)
/* Associate p2p0 network interface with new wdev */
wdev->netdev = net;
- /* store p2p net ptr for further reference. Note that iflist won't have this
- * entry as there corresponding firmware interface is a "Hidden" interface.
- */
- if (wl->p2p_net) {
- CFGP2P_ERR(("p2p_net defined already.\n"));
- return -EINVAL;
- } else {
- wl->p2p_wdev = wdev;
- wl->p2p_net = net;
- }
-
ret = register_netdev(net);
if (ret) {
CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
- goto fail;
+ free_netdev(net);
+ kfree(wdev);
+ return -ENODEV;
}
+ /* store p2p net ptr for further reference. Note that iflist won't have this
+ * entry as there corresponding firmware interface is a "Hidden" interface.
+ */
+ wl->p2p_wdev = wdev;
+ wl->p2p_net = net;
+
printk("%s: P2P Interface Registered\n", net->name);
return ret;
-fail:
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
- net->open = NULL;
-#else
- net->netdev_ops = NULL;
-#endif
-
- if (net) {
- unregister_netdev(net);
- free_netdev(net);
- }
-
- return -ENODEV;
}
s32
@@ -2205,7 +2246,13 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl)
}
static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- CFGP2P_DBG(("(%s) is not used for data operations. Droping the packet. \n", ndev->name));
+ if (skb)
+ {
+ CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n",
+ ndev->name));
+ dev_kfree_skb_any(skb);
+ }
+
return 0;
}
@@ -2281,3 +2328,8 @@ static int wl_cfgp2p_if_stop(struct net_device *net)
BIT(NL80211_IFTYPE_P2P_GO)));
return 0;
}
+
+bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops)
+{
+ return (if_ops == &wl_cfgp2p_if_ops);
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index d465b9d..aef21ec 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -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_cfgp2p.h 358702 2012-09-25 06:48:56Z $
+ * $Id: wl_cfgp2p.h 368091 2012-11-12 04:28:31Z $
*/
#ifndef _wl_cfgp2p_h_
#define _wl_cfgp2p_h_
@@ -110,15 +110,16 @@ enum wl_cfgp2p_status {
WLP2P_STATUS_ACTION_TX_COMPLETED,
WLP2P_STATUS_ACTION_TX_NOACK,
WLP2P_STATUS_SCANNING,
- WLP2P_STATUS_GO_NEG_PHASE
+ WLP2P_STATUS_GO_NEG_PHASE,
+ WLP2P_STATUS_DISC_IN_PROGRESS
};
-#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p->bss_idx[type].dev)
-#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p->bss_idx[type].bssidx)
-#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie)
-#define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data)
-#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
+#define wl_to_p2p_bss_ndev(wl, type) ((wl)->p2p->bss_idx[type].dev)
+#define wl_to_p2p_bss_bssidx(wl, type) ((wl)->p2p->bss_idx[type].bssidx)
+#define wl_to_p2p_bss_saved_ie(wl, type) ((wl)->p2p->bss_idx[type].saved_ie)
+#define wl_to_p2p_bss_private(wl, type) ((wl)->p2p->bss_idx[type].private_data)
+#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \
@@ -134,10 +135,12 @@ enum wl_cfgp2p_status {
/* dword align allocation */
#define WLC_IOCTL_MAXLEN 8192
+#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) "
+
#define CFGP2P_ERR(args) \
do { \
if (wl_dbg_level & WL_DBG_ERR) { \
- printk(KERN_INFO "CFGP2P-ERROR) %s : ", __func__); \
+ printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \
printk args; \
} \
} while (0)
@@ -237,6 +240,8 @@ wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx);
extern s32
wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev);
+extern struct net_device *
+wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx);
extern s32
@@ -295,6 +300,9 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl);
extern s32
wl_cfgp2p_unregister_ndev(struct wl_priv *wl);
+extern bool
+wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops);
+
/* WiFi Direct */
#define SOCIAL_CHAN_1 1
#define SOCIAL_CHAN_2 6
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
index 8e0ed4d..639a4d3 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -335,7 +335,7 @@ int wldev_set_band(
}
int wldev_set_country(
- struct net_device *dev, char *country_code)
+ struct net_device *dev, char *country_code, bool notify)
{
int error = -1;
wl_country_t cspec = {{0}, 0, {0}};
@@ -370,7 +370,7 @@ int wldev_set_country(
__FUNCTION__, country_code, cspec.ccode, cspec.rev));
return error;
}
- dhd_bus_country_set(dev, &cspec);
+ dhd_bus_country_set(dev, &cspec, notify);
WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
__FUNCTION__, country_code, cspec.ccode, cspec.rev));
}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
index f9bf425..15c3f02 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.h
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -84,9 +84,9 @@ s32 wldev_iovar_setint_bsscfg(
struct net_device *dev, s8 *iovar, s32 val, s32 bssidx);
extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec);
-extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec);
+extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify);
extern void dhd_bus_band_set(struct net_device *dev, uint band);
-extern int wldev_set_country(struct net_device *dev, char *country_code);
+extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify);
extern int net_os_wake_lock(struct net_device *dev);
extern int net_os_wake_unlock(struct net_device *dev);
extern int net_os_wake_lock_timeout(struct net_device *dev);