From d60ec08410dd639e48d00a8c22214a0cde40fd75 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 1 May 2012 11:00:21 -0700 Subject: [PATCH] net: wireless: bcmdhd: Update to Version 5.90.195.61 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - Deauth frame from p2p GO to client doesn't go from firmware if we do del_virtual_iface immediately. Putting a delay after sending deauth frame to allowed FW to send out deauth frame. - IF_DEL operation was timing out due to wrong status check. Fixed it and added few debug prints. - Sending Provision Discovery directly to GO instead of doing an internal scan. Also put the internal scan count to 3 to have better timings for GO-NEG. - Increase beacon timeout only for concurrent mode. For STA only operation, use the default beacon timeout value (4). - If scan abort is due to timeout, aborting the scan in FW is not required. Moreover, as this scan_timeout call is coming in timer interrupt context, all blocking calls such as fw scan abort will result in kernel panic : don’t call abort in Firmware. - Add p2p_cancel_listen routine. Fix p2p_listen_complete related kernel crash seen while turning off WiFi. Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd.h | 10 +- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 25 ++++- drivers/net/wireless/bcmdhd/dhd_common.c | 8 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 6 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 5 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 91 +++++++++++++------ drivers/net/wireless/bcmdhd/wl_cfg80211.h | 5 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 49 ++++++++-- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 7 +- 10 files changed, 154 insertions(+), 60 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index dc2e3828ba2b..5cace1f91a5c 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -24,11 +24,12 @@ * 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 325862 2012-04-04 22:59:48Z $ + * $Id: dhd.h 328934 2012-04-23 05:15:42Z $ */ - - +/**************** + * Common types * + */ #ifndef _dhd_h_ #define _dhd_h_ @@ -90,6 +91,9 @@ enum dhd_bus_state { #define DHD_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ #define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ +#define DHD_BEACON_TIMEOUT_NORMAL 4 +#define DHD_BEACON_TIMEOUT_HIGH 10 + enum dhd_bus_wake_state { WAKE_LOCK_OFF, WAKE_LOCK_PRIV, diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 2503f51ec574..183891df160a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -41,7 +41,9 @@ static int dhd_dongle_up = FALSE; static s32 wl_dongle_up(struct net_device *ndev, u32 up); - +/** + * Function implementations + */ s32 dhd_cfg80211_init(struct wl_priv *wl) { @@ -70,13 +72,22 @@ s32 dhd_cfg80211_down(struct wl_priv *wl) s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) { dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + int bcn_timeout = DHD_BEACON_TIMEOUT_HIGH; + char iovbuf[30]; + dhd->op_mode |= val; WL_ERR(("Set : op_mode=%d\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); -#endif +#endif /* ARP_OFFLOAD_SUPPORT */ + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + return 0; } @@ -84,13 +95,21 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) { dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + int bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL; + char iovbuf[30]; + dhd->op_mode &= ~CONCURENT_MASK; WL_ERR(("Clean : op_mode=%d\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); -#endif +#endif /* ARP_OFFLOAD_SUPPORT */ + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); return 0; } diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index ca5a76ee3153..60e1449c97d7 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 319098 2012-03-07 01:05:20Z $ + * $Id: dhd_common.c 329682 2012-04-26 09:20:38Z $ */ #include #include @@ -996,6 +996,9 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, datalen = ntoh32_ua((void *)&event->datalen); evlen = datalen + sizeof(bcm_event_t); + DHD_TRACE(("RX: event_type:%d flags:%d status:%d reason:%d \n", + type, flags, status, reason)); + switch (type) { #ifdef PROP_TXSTATUS case WLC_E_FIFO_CREDIT_MAP: @@ -1723,6 +1726,7 @@ fail: /* * returns = TRUE if associated, FALSE if not associated + * third paramter retval can return error from error */ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) { @@ -1891,7 +1895,7 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); return ret; } -#endif +#endif /* !WL_SCHED_SCAN */ /* 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 667e1b91bab6..b177f324fb50 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 325862 2012-04-04 22:59:48Z $ + * $Id: dhd_linux.c 329682 2012-04-26 09:20:38Z $ */ #include @@ -1472,6 +1472,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) */ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; PKTFREE(dhdp->osh, pktbuf, TRUE); + DHD_TRACE(("RX: wlfc header \n")); continue; } #endif @@ -2962,7 +2963,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = 0; - uint bcn_timeout = 10; + uint bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL; + uint retry_max = 3; #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index d445f2608088..7fdd31443a85 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 325395 2012-04-03 03:57:43Z $ + * $Id: dhd_sdio.c 326662 2012-04-10 06:38:08Z $ */ #include @@ -4616,8 +4616,7 @@ clkwait: int ret, i; uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; - if (((bus->sih->chip == BCM4329_CHIP_ID) || /* limit to 4329 & 4330 for now */ - (bus->sih->chip == BCM4330_CHIP_ID)) && (*frame_seq != bus->tx_seq)) { + if (*frame_seq != bus->tx_seq) { DHD_INFO(("%s IOCTL frame seq lag detected!" " frm_seq:%d != bus->tx_seq:%d, corrected\n", __FUNCTION__, *frame_seq, bus->tx_seq)); diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index b3560bd9203f..3bff73e2a6bc 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 53 +#define EPI_INCREMENTAL_NUMBER 61 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 53 +#define EPI_VERSION 5, 90, 195, 61 -#define EPI_VERSION_NUM 0x055ac335 +#define EPI_VERSION_NUM 0x055ac33d #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.53" +#define EPI_VERSION_STR "5.90.195.61" #endif diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 4b83d2aeea71..839f907d5798 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -100,7 +100,10 @@ static const struct ieee80211_regdomain brcm_regdom = { * 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, 0), + REG_RULE(2484-10, 2484+10, 20, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_OFDM), /* IEEE 802.11a, channel 36..64 */ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), /* IEEE 802.11a, channel 100..165 */ @@ -735,7 +738,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 mode = 0; #if defined(WL_ENABLE_P2P_IF) s32 dhd_mode = 0; -#endif +#endif /* (WL_ENABLE_P2P_IF) */ chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; @@ -807,7 +810,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-EAGAIN); } } - if (!p2p_is_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); @@ -819,7 +822,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - + wldev_iovar_setint(_ndev, "mpc", 0); + wl_notify_escan_complete(wl, _ndev, true, true); /* In concurrency case, STA may be already associated in a particular channel. * so retrieve the current channel of primary interface and then start the virtual * interface on that. @@ -874,8 +878,10 @@ 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)); -#endif - +#endif /* (WL_ENABLE_P2P_IF) */ + /* 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; @@ -920,7 +926,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); if (wl->p2p->vif_created) { - if (wl->scan_request) { + if (wl_get_drv_status(wl, SCANNING, dev)) { wl_notify_escan_complete(wl, dev, true, true); } wldev_iovar_setint(dev, "mpc", 1); @@ -948,7 +954,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) WL_DBG(("IFDEL operation done\n")); #if defined(WL_ENABLE_P2P_IF) DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); -#endif +#endif /* (WL_ENABLE_P2P_IF)) */ } else { WL_ERR(("IFDEL didn't complete properly\n")); } @@ -972,7 +978,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); - WL_DBG(("Enter \n")); + WL_DBG(("Enter type %d\n", type)); switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: @@ -1003,8 +1009,10 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, wl_set_mode_by_netdev(wl, ndev, mode); if (wl->p2p_supported && wl->p2p->vif_created) { WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, - p2p_on(wl))); + p2p_on(wl))); wldev_iovar_setint(ndev, "mpc", 0); + wl_notify_escan_complete(wl, ndev, true, true); + /* In concurrency case, STA may be already associated in a particular * channel. so retrieve the current channel of primary interface and * then start the virtual interface on that. @@ -1121,6 +1129,7 @@ wl_cfg80211_ifdel_ops(struct net_device *ndev) WL_DBG(("index : %d\n", index)); } + /* Wake up any waiting thread */ wake_up_interruptible(&wl->netif_change_event); @@ -2007,7 +2016,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); if (is_wps_conn(sme)) { - err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + if (sme->privacy) + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + else + /* WPS-2.0 allowes no security */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); } else { WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); err = wldev_iovar_setint_bsscfg(dev, "wsec", @@ -2847,7 +2860,6 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, err = -ENODEV; if (!wl_get_drv_status(wl, CONNECTED, dev) || (dhd_is_associated(dhd, NULL, &err) == FALSE)) { - WL_ERR(("NOT assoc: %d\n", err)); goto get_station_err; } @@ -3168,7 +3180,7 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) /* Our scan params have 1 channel and 0 ssids */ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | - (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); *out_params_size = params_size; /* rtn size to the caller */ return params; @@ -3195,7 +3207,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ndev = dev; } - if (wl->scan_request) { + if (wl_get_drv_status(wl, SCANNING, ndev)) { wl_notify_escan_complete(wl, ndev, true, true); } target_channel = ieee80211_frequency_to_channel(channel->center_freq); @@ -3207,7 +3219,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, *cookie = id; cfg80211_ready_on_channel(dev, *cookie, channel, channel_type, duration, GFP_KERNEL); - if (!p2p_is_on(wl)) { + if (wl->p2p && !wl->p2p->on) { get_primary_mac(wl, &primary_mac); wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); @@ -3331,7 +3343,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *channel, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, - const u8* buf, size_t len, u64 *cookie) + const u8* buf, size_t len, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) + bool no_cck, +#endif + u64 *cookie) { wl_action_frame_t *action_frame; wl_af_params_t *af_params; @@ -3418,6 +3434,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, WL_DBG(("Disconnect STA : %s scb_val.val %d\n", bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val)); + /* Wait for the deauth event to come, supplicant will do the delete iface immediately + * and we will have problem in sending deauth frame if we delete the bss in firmware + */ + wl_delay(400); cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -3521,7 +3541,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, } if (IS_P2P_SOCIAL(af_params->channel) && - (IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) || + (IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], action_frame->len) || IS_GAS_REQ(sd_act_frm, action_frame->len)) && wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { /* channel offload require P2P IE for Probe request @@ -3534,7 +3554,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, } else { ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (!ack) { - for (retry = 1; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + for (retry = 1; retry < retry_cnt; retry++) { ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (ack) @@ -4771,17 +4791,24 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, bool act; s32 err = 0; u32 event = ntoh32(e->event_type); + u32 reason; if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { wl_notify_connect_status_ap(wl, ndev, e, data); } else { WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", ntoh32(e->event_type), ntoh32(e->status), ndev)); + if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) { + reason = ntoh32(e->reason); + wl->deauth_reason = reason; + WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason)); + } if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl->deauth_reason = 0; if (wl_is_ibssmode(wl, ndev)) { printk("cfg80211_ibss_joined\n"); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, @@ -4809,7 +4836,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_get_drv_status(wl, CONNECTED, ndev)) { scb_val_t scbval; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - printk("link down, call cfg80211_disconnected\n"); wl_clr_drv_status(wl, CONNECTED, ndev); if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { /* To make sure disconnect, explictly send dissassoc @@ -4821,7 +4847,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, scbval.val = htod32(scbval.val); wldev_ioctl(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason)); + cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL); wl_link_down(wl); wl_init_prof(wl, ndev); } @@ -5821,7 +5848,7 @@ static void wl_scan_timeout(unsigned long data) if (wl->scan_request) { WL_ERR(("timer expired\n")); if (wl->escan_on) - wl_notify_escan_complete(wl, wl->escan_info.ndev, false, true); + wl_notify_escan_complete(wl, wl->escan_info.ndev, true, false); else wl_notify_iscan_complete(wl_to_iscan(wl), true); } @@ -5877,7 +5904,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, struct wl_priv *wl = wlcfg_drv_priv; WL_DBG(("Enter \n")); - if (!wdev || dev == wl_to_prmry_ndev(wl)) + if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) return NOTIFY_DONE; switch (state) { case NETDEV_UNREGISTER: @@ -5942,7 +5969,7 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, } } } - if (!in_atomic()) + if (timer_pending(&wl->scan_timeout)) del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); @@ -5984,7 +6011,6 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_scan_results_t *list; u32 bi_length; u32 i; - u8 *p2p_dev_addr = NULL; WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); @@ -6033,8 +6059,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, } if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { - p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); - if (p2p_dev_addr && !memcmp(p2p_dev_addr, + if (!memcmp(bi->BSSID.octet, wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) { s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec)); WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel)); @@ -6187,6 +6212,7 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->iscan_kickstart = false; wl->active_scan = true; wl->rf_blocked = false; + wl->deauth_reason = 0; spin_lock_init(&wl->cfgdrv_lock); mutex_init(&wl->ioctl_buf_sync); init_waitqueue_head(&wl->netif_change_event); @@ -6711,12 +6737,16 @@ s32 wl_update_wiphybands(struct wl_priv *wl) } if ((index >= 0) && nmode) { wiphy->bands[index]->ht_cap.cap = - IEEE80211_HT_CAP_DSSSCCK40 - | IEEE80211_HT_CAP_MAX_AMSDU | IEEE80211_HT_CAP_RX_STBC; + 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_16K; + 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); @@ -7043,7 +7073,8 @@ static void wl_init_eq_lock(struct wl_priv *wl) static void wl_delay(u32 ms) { - if (in_atomic() || ms < 1000 / HZ) { + if (ms < 1000 / HZ) { + cond_resched(); mdelay(ms); } else { msleep(ms); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 818eff594115..fba853149c35 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -131,8 +131,8 @@ do { \ #define IFACE_MAX_CNT 2 #define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ -#define WL_CHANNEL_SYNC_RETRY 1 -#define WL_ACT_FRAME_RETRY 5 +#define WL_CHANNEL_SYNC_RETRY 3 +#define WL_ACT_FRAME_RETRY 4 #define WL_INVALID -1 @@ -449,6 +449,7 @@ struct wl_priv { #endif /* WL_SCHED_SCAN */ bool sched_scan_running; /* scheduled scan req status */ u16 hostapd_chan; /* remember chan requested by framework for hostapd */ + u16 deauth_reason; /* Place holder to save deauth/disassoc reasons */ }; 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/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 880123e067dc..cfa5ac3f5ec6 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -105,6 +105,7 @@ bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) return false; } + bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) { @@ -128,6 +129,7 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return false; } + void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) { wifi_p2p_pub_act_frame_t *pact_frm; @@ -271,7 +273,6 @@ wl_cfgp2p_init_priv(struct wl_priv *wl) wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; - spin_lock_init(&wl->p2p->timer_lock); return BCME_OK; } @@ -318,7 +319,7 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); if (ret && ret != BCME_UNSUPPORTED) { - CFGP2P_ERR(("failed to update device address\n")); + CFGP2P_ERR(("failed to update device address ret %d\n", ret)); } return ret; } @@ -539,7 +540,7 @@ wl_cfgp2p_init_discovery(struct wl_priv *wl) /* Set the initial discovery state to SCAN */ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, - wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); if (unlikely(ret != 0)) { CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); @@ -690,7 +691,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, #define P2PAPI_SCAN_NPROBES 1 #define P2PAPI_SCAN_DWELL_TIME_MS 50 #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 -#define P2PAPI_SCAN_HOME_TIME_MS 10 +#define P2PAPI_SCAN_HOME_TIME_MS 60 struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); wl_set_p2p_status(wl, SCANNING); /* Allocate scan params which need space for 3 channels and 0 ssids */ @@ -1180,12 +1181,15 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, s32 ret = BCME_OK; CFGP2P_DBG((" Enter\n")); + + /* If p2p_info is de-initialized, do nothing */ + if (!wl->p2p) + return ret; + if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { wl_set_p2p_status(wl, LISTEN_EXPIRED); if (timer_pending(&wl->p2p->listen_timer)) { - spin_lock_bh(&wl->p2p->timer_lock); del_timer_sync(&wl->p2p->listen_timer); - spin_unlock_bh(&wl->p2p->timer_lock); } cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); @@ -1212,6 +1216,33 @@ wl_cfgp2p_listen_expired(unsigned long data) wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); } +/* + * Routine for cancelling the P2P LISTEN + */ +s32 +wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, + bool notify) +{ + WL_DBG(("Enter \n")); + + /* Irrespective of whether timer is running or not, reset + * the LISTEN state. + */ + wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + + if (timer_pending(&wl->p2p->listen_timer)) { + del_timer_sync(&wl->p2p->listen_timer); + + if (notify) + cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, + &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); + } + + + return 0; +} + /* * Do a P2P Listen on the given channel for the given duration. * A listen consists of sitting idle and responding to P2P probe requests @@ -1531,8 +1562,10 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) s32 wl_cfgp2p_down(struct wl_priv *wl) { - if (timer_pending(&wl->p2p->listen_timer)) - del_timer_sync(&wl->p2p->listen_timer); + + wl_cfgp2p_cancel_listen(wl, + wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE); + wl_cfgp2p_deinit_priv(wl); return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 1e5b1197e92d..be497c3e2426 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -77,7 +77,6 @@ struct p2p_info { wl_p2p_sched_t noa; wl_p2p_ops_t ops; wlc_ssid_t ssid; - spinlock_t timer_lock; }; /* dongle status */ @@ -268,14 +267,16 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); #define WL_P2P_INTERFACE_PREFIX "p2p" #define WL_P2P_TEMP_CHAN "11" +/* If the provision discovery is for JOIN operations, then we need not do an internal scan to find GO */ +#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL ) #define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) -#define IS_P2P_PUB_ACT_REQ(frame, len) (wl_cfgp2p_is_pub_action(frame, len) && \ +#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) (wl_cfgp2p_is_pub_action(frame, len) && \ ((frame->subtype == P2P_PAF_GON_REQ) || \ (frame->subtype == P2P_PAF_INVITE_REQ) || \ - (frame->subtype == P2P_PAF_PROVDIS_REQ))) + ((frame->subtype == P2P_PAF_PROVDIS_REQ) && IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len)))) #define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) #endif /* _wl_cfgp2p_h_ */ -- 2.34.1