diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2012-12-19 12:56:39 -0800 |
---|---|---|
committer | Ziyan <jaraidaniel@gmail.com> | 2016-05-01 23:35:11 +0200 |
commit | 1456f0fbca72df2b67cd86a688d9c59ea374a0b6 (patch) | |
tree | 962b9f4cd2f70ec0ec91f3e6898c7ba849ebe875 | |
parent | b14eb80091a3f11a69448bafc63a5501c613a487 (diff) | |
download | kernel_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>
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(¶ms->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", ¶m, 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); |