From 4b04b815711fe48b87912e830cf330a84fefc329 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Thu, 15 Mar 2012 12:47:26 -0700 Subject: [PATCH] net: wireless: bcmdhd: Update to Version 5.90.195.35 - Add SoftAP auto-channel support - P2P fixes Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 2 +- drivers/net/wireless/bcmdhd/dhd.h | 1 - drivers/net/wireless/bcmdhd/dhd_common.c | 15 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 43 +++- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 196 +++++++++++------- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 1 + drivers/net/wireless/bcmdhd/wldev_common.c | 50 +++++ drivers/net/wireless/bcmdhd/wldev_common.h | 2 + 9 files changed, 226 insertions(+), 92 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 79420e6efff6..4372c876912f 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -8,7 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -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 \ - -DSET_RANDOM_MAC_SOFTAP -DENABLE_P2P_INTERFACE -DDHD_USE_EARLYSUSPEND \ + -DSET_RANDOM_MAC_SOFTAP -DWL_ENABLE_P2P_IF -DDHD_USE_EARLYSUSPEND \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index d0306176b164..2150f0212ddc 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -212,7 +212,6 @@ typedef struct dhd_pub { * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile */ -/* #define ENABLE_P2P_INTERFACE 1 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) struct wake_lock wakelock[WAKE_LOCK_MAX]; diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index a99dd49af4c6..4fa07fb888b4 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 316272 2012-02-21 22:35:51Z $ + * $Id: dhd_common.c 319098 2012-03-07 01:05:20Z $ */ #include #include @@ -1814,11 +1814,14 @@ exit: bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) { #ifdef WL_CFG80211 -#ifndef ENABLE_P2P_INTERFACE - /* To be back compatble with ICS MR1 release where p2p interface disable but wlan0 used for p2p */ +#ifndef WL_ENABLE_P2P_IF + /* To be back compatble with ICS MR1 release where p2p interface + * disable but wlan0 used for p2p + */ if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) || - ((dhd->op_mode & WFD_MASK) == WFD_MASK)) + ((dhd->op_mode & WFD_MASK) == WFD_MASK)) { return TRUE; + } else #else /* concurent mode with p2p interface for wfd and wlan0 for sta */ @@ -1828,7 +1831,7 @@ bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) return TRUE; } else -#endif +#endif /* WL_ENABLE_P2P_IF */ #endif /* WL_CFG80211 */ return FALSE; } @@ -1880,10 +1883,12 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) memset(iovbuf, 0, sizeof(iovbuf)); +#ifndef WL_SCHED_SCAN if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) { DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); return ret; } +#endif /* Enable/disable PNO */ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 5ed76f9a4ce8..14d3660affcf 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 316856 2012-02-23 21:44:34Z $ + * $Id: dhd_linux.c 319136 2012-03-07 03:10:36Z $ */ #include @@ -426,7 +426,7 @@ static void dhd_net_if_lock_local(dhd_info_t *dhd); static void dhd_net_if_unlock_local(dhd_info_t *dhd); static void dhd_suspend_lock(dhd_pub_t *dhdp); static void dhd_suspend_unlock(dhd_pub_t *dhdp); -#if !defined(AP) && defined(WLP2P) +#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF) static u32 dhd_concurrent_fw(dhd_pub_t *dhd); #endif @@ -588,8 +588,9 @@ static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) /* Set flag when early suspend was called */ dhdp->in_suspend = val; if ((force || !dhdp->suspend_disable_flag) && - (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) + (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) { ret = dhd_set_suspend(val, dhdp); + } DHD_OS_WAKE_UNLOCK(dhdp); return ret; } @@ -1284,11 +1285,13 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); netif_stop_queue(net); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) /* Send Event when bus down detected during data session */ if (dhd->pub.busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); net_os_send_hang_message(net); } +#endif DHD_OS_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } @@ -2010,6 +2013,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) if (!dhdp) return FALSE; if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) && @@ -2019,6 +2023,7 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) net_os_send_hang_message(net); return TRUE; } +#endif return FALSE; } @@ -2888,7 +2893,7 @@ dhd_bus_start(dhd_pub_t *dhdp) return 0; } -#if !defined(AP) && defined(WLP2P) +#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF) /* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware @@ -2950,7 +2955,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ #endif -#if defined(AP) || defined(WLP2P) +#if defined(AP) || (defined(WLP2P) && defined(WL_ENABLE_P2P_IF)) uint32 apsta = 1; /* Enable APSTA mode */ #endif /* defined(AP) || defined(WLP2P) */ #ifdef GET_CUSTOM_MAC_ENABLE @@ -3008,7 +3013,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* SET_RANDOM_MAC_SOFTAP */ DHD_TRACE(("Firmware = %s\n", fw_path)); -#if !defined(AP) && defined(WLP2P) +#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF) /* Check if firmware with WFD support used */ if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) || (dhd_concurrent_fw(dhd))) { @@ -3029,6 +3034,26 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if !defined(AP) && defined(WL_CFG80211) /* Check if firmware with HostAPD support used */ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { + /* Turn off wme if we are having only g ONLY firmware */ + bcm_mkiovar("nmode", 0, 0, buf, sizeof(buf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), + FALSE, 0)) < 0) { + DHD_ERROR(("%s:get nmode failed error (%d)\n", __FUNCTION__, ret)); + } + else { + DHD_TRACE(("%s:get nmode returned %d\n", __FUNCTION__,buf[0])); + } + if (buf[0] == 0) { + int wme = 0; + bcm_mkiovar("wme", (char *)&wme, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s set wme for HostAPD failed %d\n", __FUNCTION__, ret)); + } + else { + DHD_TRACE(("%s set wme succeeded for g ONLY firmware\n", __FUNCTION__)); + } + } /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, @@ -3764,10 +3789,10 @@ dhd_module_init(void) #endif /* defined(WL_CFG80211) */ return error; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) fail_2: dhd_bus_unregister(); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +#endif fail_1: #if defined(CONFIG_WIFI_CONTROL_FUNC) wl_android_wifictrl_func_del(); @@ -4388,6 +4413,7 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4414,6 +4440,7 @@ int net_os_send_hang_message(struct net_device *dev) } return ret; } +#endif void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) { diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index ff386de6737b..ddb28aed0baf 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 30 +#define EPI_INCREMENTAL_NUMBER 35 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 30 +#define EPI_VERSION 5, 90, 195, 35 -#define EPI_VERSION_NUM 0x055ac31e +#define EPI_VERSION_NUM 0x055ac323 #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.30" +#define EPI_VERSION_STR "5.90.195.35" #endif diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index c920448e722f..dab24e255db8 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -71,6 +71,7 @@ u32 wl_dbg_level = WL_DBG_ERR; #define MAX_WAIT_TIME 1500 #define WL_SCAN_ACTIVE_TIME 40 #define WL_SCAN_PASSIVE_TIME 130 +#define WL_FRAME_LEN 300 #define DNGL_FUNC(func, parameters) func parameters; #define COEX_DHCP @@ -94,13 +95,12 @@ static const struct ieee80211_regdomain brcm_regdom = { REG_RULE(2467-10, 2472+10, 20, 6, 20, NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), - /* IEEE 802.11 channel 14 - Only JP enables - * this and for 802.11b only + /* + * IEEE 802.11 channel 14 - is for JP only, + * we need cfg80211 to allow it (reg_flags = 0); so that + * hostapd could request auto channel by sending down ch 14 */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | - NL80211_RRF_NO_OFDM), + REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), /* IEEE 802.11a, channel 36..64 */ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), /* IEEE 802.11a, channel 100..165 */ @@ -510,22 +510,7 @@ static struct ieee80211_supported_band __wl_band_2ghz = { .channels = __wl_2ghz_channels, .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, - .n_bitrates = wl_g_rates_size, -#if defined(ENABLE_P2P_INTERFACE) - /* wpa_supplicant sets wmm_enabled based on whether ht_cap - * is present or not. The wmm_enabled is inturn used to - * set the replay counters in the RSN IE. Without this - * the 4way handshake will fail complaining that IE in beacon - * doesn't match with the IE present in the 3/4 EAPOL msg. - */ - .ht_cap = { - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, - .ht_supported = TRUE, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 - } -#endif + .n_bitrates = wl_g_rates_size }; static struct ieee80211_supported_band __wl_band_5ghz_a = { @@ -533,22 +518,7 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .channels = __wl_5ghz_a_channels, .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size, -#if defined(ENABLE_P2P_INTERFACE) - /* wpa_supplicant sets wmm_enabled based on whether ht_cap - * is present or not. The wmm_enabled is inturn used to - * set the replay counters in the RSN IE. Without this - * the 4way handshake will fail complaining that IE in beacon - * doesn't match with the IE present in the 3/4 EAPOL msg. - */ - .ht_cap = { - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, - .ht_supported = TRUE, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 - } -#endif + .n_bitrates = wl_a_rates_size }; static const u32 __wl_cipher_suites[] = { @@ -901,6 +871,12 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, else if (type == NL80211_IFTYPE_P2P_GO) dhd_mode = P2P_GO_ENABLED; DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); + /* Start the P2P I/F with PM disabled. Enable PM from + * the framework + */ + if ((type == NL80211_IFTYPE_P2P_CLIENT) || ( + type == NL80211_IFTYPE_P2P_GO)) + vwdev->ps = NL80211_PS_DISABLED; } else { /* put back the rtnl_lock again */ if (rollback_lock) @@ -1234,7 +1210,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK; params->channel_list[i] |= chanspec; WL_SCAN(("Chan : %d, Channel spec: %x \n", - channel, params->channel_list[i])); + channel, params->channel_list[i])); params->channel_list[i] = htod16(params->channel_list[i]); } } else { @@ -2913,18 +2889,13 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); + WL_DBG(("Enter : power save %s\n", (enabled ? "enable" : "disable"))); if (wl->p2p_net == dev) { return err; } pm = enabled ? PM_FAST : PM_OFF; - /* Do not enable the power save after assoc if it is p2p interface */ - if (wl->p2p && wl->p2p->vif_created) { - WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n")); - pm = PM_OFF; - } pm = htod32(pm); - WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); if (unlikely(err)) { if (err == -ENODEV) @@ -2933,6 +2904,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("error (%d)\n", err)); return err; } + WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); return err; } @@ -3429,7 +3401,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, sizeof(scb_val_t), true); WL_DBG(("Disconnect STA : %s scb_val.val %d\n", - bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val)); + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), + scb_val.val)); cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -3626,6 +3599,14 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, dev = wl_to_prmry_ndev(wl); } channel = ieee80211_frequency_to_channel(chan->center_freq); + + if (wl_get_drv_status(wl, AP_CREATING, dev) && channel == 14) { + WL_TRACE(("<0> %s: as!!! in AP creating mode, save chan num:%d\n", + __FUNCTION__, channel)); + wl->hostapd_chan = channel; + return err; + } + WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", dev->ifindex, channel_type, channel)); err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true); @@ -4012,6 +3993,26 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("setting AP mode failed %d \n", err)); return err; } + + /* if requested, do softap ch autoselect */ + if (wl->hostapd_chan == 14) { + int auto_chan; + if ((err = wldev_get_auto_channel(dev, &auto_chan)) != 0) { + WL_ERR(("softap: auto chan select failed," + " will use ch 6\n")); + auto_chan = 6; + } else { + printf("<0>softap: got auto ch:%d\n", auto_chan); + } + err = wldev_ioctl(dev, WLC_SET_CHANNEL, + &auto_chan, sizeof(auto_chan), true); + if (err < 0) { + WL_ERR(("softap: WLC_SET_CHANNEL error %d chip" + " may not be supporting this channel\n", err)); + return err; + } + } + /* find the RSN_IE */ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, DOT11_MNG_RSN_ID)) != NULL) { @@ -4529,7 +4530,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; -#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) { #else @@ -4613,11 +4614,9 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) /* The mainline kernel >= 3.2.0 has support for indicating new/del station * to AP/P2P GO via events. If this change is backported to kernel for which - * this driver is being built, set CFG80211_STA_EVENT_AVAILABLE to 1. You - * should use this new/del sta event mechanism for BRCM supplicant from BRANCH - * HOSTAP_BRANCH_0_15 (ver >= 15_1). + * this driver is being built, then define WL_CFG80211_STA_EVENT. You + * should use this new/del sta event mechanism for BRCM supplicant >= 22. */ -#define CFG80211_STA_EVENT_AVAILABLE 0 static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -4627,13 +4626,13 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, u32 reason = ntoh32(e->reason); u32 len = ntoh32(e->datalen); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) bool isfree = false; u8 *mgmt_frame; u8 bsscfgidx = e->bsscfgidx; s32 freq; s32 channel; - u8 body[200]; + u8 body[WL_FRAME_LEN]; u16 fc = 0; struct ieee80211_supported_band *band; struct ether_addr da; @@ -4642,16 +4641,21 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, channel_info_t ci; #else struct station_info sinfo; -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE */ +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) memset(body, 0, sizeof(body)); memset(&bssid, 0, ETHER_ADDR_LEN); WL_DBG(("Enter event %d ndev %p\n", event, ndev)); if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) return WL_INVALID; + if (len > WL_FRAME_LEN) { + WL_ERR(("Received frame length %d from dongle is greater than" + " allocated body buffer len %d", len, WL_FRAME_LEN)); + goto exit; + } memcpy(body, data, len); wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); @@ -4710,7 +4714,7 @@ exit: if (isfree) kfree(mgmt_frame); return err; -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ sinfo.filled = 0; if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && reason == DOT11_SC_SUCCESS) { @@ -4727,7 +4731,7 @@ exit: } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ return err; } @@ -5329,10 +5333,10 @@ exit: } #ifdef WL_SCHED_SCAN -/* If target scan is not reliable, set the below define to "0" to do a +/* If target scan is not reliable, set the below define to "1" to do a * full escan */ -#define FULL_ESCAN_ON_PFN_NET_FOUND 1 +#define FULL_ESCAN_ON_PFN_NET_FOUND 0 static s32 wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -5421,9 +5425,9 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, wl_set_drv_status(wl, SCANNING, ndev); #if FULL_ESCAN_ON_PFN_NET_FOUND - err = wl_do_escan(wl, wiphy, ndev, &request); -#else err = wl_do_escan(wl, wiphy, ndev, NULL); +#else + err = wl_do_escan(wl, wiphy, ndev, &request); #endif if (err) { wl_clr_drv_status(wl, SCANNING, ndev); @@ -5845,9 +5849,22 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, return NOTIFY_DONE; switch (state) { case NETDEV_UNREGISTER: - /* after calling list_del_rcu(&wdev->list) */ - wl_dealloc_netinfo(wl, ndev); - break; + /* after calling list_del_rcu(&wdev->list) */ + wl_dealloc_netinfo(wl, ndev); + break; + case NETDEV_GOING_DOWN: + /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. + * In front of door, the function checks + * whether current scan is working or not. + * If the scanning is still working, wdev_cleanup_work call WARN_ON and + * make the scan done forcibly. + */ + if (wl_get_drv_status(wl, SCANNING, dev)) { + if (wl->escan_on) { + wl_notify_escan_complete(wl, dev, true, true); + } + } + break; } return NOTIFY_DONE; } @@ -6172,7 +6189,7 @@ static void wl_deinit_priv(struct wl_priv *wl) unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); } -#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) static s32 wl_cfg80211_attach_p2p(void) { struct wl_priv *wl = wlcfg_drv_priv; @@ -6207,7 +6224,7 @@ static s32 wl_cfg80211_detach_p2p(void) return 0; } -#endif /* defined(WLP2P) && (ENABLE_P2P_INTERFACE) */ +#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ s32 wl_cfg80211_attach_post(struct net_device *ndev) { @@ -6222,7 +6239,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) if (wl && !wl_get_drv_status(wl, READY, ndev)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { -#if !defined(ENABLE_P2P_INTERFACE) +#if !defined(WL_ENABLE_P2P_IF) wl->wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO)); @@ -6230,7 +6247,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) if ((err = wl_cfgp2p_init_priv(wl)) != 0) goto fail; -#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) if (wl->p2p_net) { /* Update MAC addr for p2p0 interface here. */ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); @@ -6242,7 +6259,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) " Couldn't update the MAC Address for p2p0 \n")); return -ENODEV; } -#endif /* defined(WLP2P) && (ENABLE_P2P_INTERFACE) */ +#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */ wl->p2p_supported = true; } @@ -6314,7 +6331,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) wlcfg_drv_priv = wl; -#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) err = wl_cfg80211_attach_p2p(); if (err) goto cfg80211_attach_out; @@ -6340,7 +6357,7 @@ void wl_cfg80211_detach(void *para) wl_cfg80211_btcoex_deinit(wl); #endif -#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) +#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) wl_cfg80211_detach_p2p(); #endif wl_setup_rfkill(wl, FALSE); @@ -6620,6 +6637,10 @@ s32 wl_update_wiphybands(struct wl_priv *wl) u32 nband = 0; u32 i = 0; s32 err = 0; + int nmode = 0; + int bw_40 = 0; + int index = 0; + WL_DBG(("Entry")); memset(bandlist, 0, sizeof(bandlist)); err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist, @@ -6632,14 +6653,43 @@ s32 wl_update_wiphybands(struct wl_priv *wl) nband = bandlist[0]; wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + + err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + + err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + for (i = 1; i <= nband && i < sizeof(bandlist); i++) { - if (bandlist[i] == WLC_BAND_5G) + index = -1; + if (bandlist[i] == WLC_BAND_5G) { wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - else if (bandlist[i] == WLC_BAND_2G) + index = IEEE80211_BAND_5GHZ; + } else if (bandlist[i] == WLC_BAND_2G) { wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + index = IEEE80211_BAND_2GHZ; + } + + if ((index >= 0) && nmode) { + wiphy->bands[index]->ht_cap.cap = + IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_MAX_AMSDU; + wiphy->bands[index]->ht_cap.ht_supported = TRUE; + wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + } + + if ((index >= 0) && bw_40) { + wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } } + wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); return err; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 41e7c678e41b..515443bc3ec2 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -446,6 +446,7 @@ struct wl_priv { struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ #endif /* WL_SCHED_SCAN */ bool sched_scan_running; /* scheduled scan req status */ + u16 hostapd_chan; /* remember chan requested by framework for hostapd */ }; static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index d9a0b93d689f..827033185035 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -366,3 +366,53 @@ int wldev_set_country( __FUNCTION__, country_code, cspec.ccode, cspec.rev)); return 0; } + +/* + * softap channel autoselect + */ +int wldev_get_auto_channel(struct net_device *dev, int *chan) +{ + int chosen = 0; + wl_uint32_list_t request; + int retry = 0; + int updown = 0; + int ret = 0; + wlc_ssid_t null_ssid; + + memset(&null_ssid, 0, sizeof(wlc_ssid_t)); + ret |= wldev_ioctl(dev, WLC_UP, &updown, sizeof(updown), true); + + ret |= wldev_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid), true); + + request.count = htod32(0); + ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request), true); + if (ret < 0) { + WLDEV_ERROR(("can't start auto channel scan:%d\n", ret)); + goto fail; + } + + while (retry++ < 15) { + + bcm_mdelay(350); + + ret = wldev_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), false); + + if ((ret == 0) && (dtoh32(chosen) != 0)) { + *chan = (uint16)chosen & 0x00FF; /* covert chanspec --> chan number */ + printf("%s: Got channel = %d, attempt:%d\n", + __FUNCTION__, *chan, retry); + break; + } + } + + if ((ret = wldev_ioctl(dev, WLC_DOWN, &updown, sizeof(updown), true)) < 0) { + WLDEV_ERROR(("%s fail to WLC_DOWN ioctl err =%d\n", __FUNCTION__, ret)); + goto fail; + } + +fail : + if (ret < 0) { + WLDEV_ERROR(("%s: return value %d\n", __FUNCTION__, ret)); + } + return ret; +} diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index 773235e4597e..f58660944420 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -107,4 +107,6 @@ int wldev_get_band(struct net_device *dev, uint *pband); int wldev_set_band(struct net_device *dev, uint band); +int wldev_get_auto_channel(struct net_device *dev, int *chan); + #endif /* __WLDEV_COMMON_H__ */ -- 2.34.1