Whenever the signal stregth decays smoothly and physical connnection is already gone and no deauth has arrived, the qcom soc is not able to indicate neither WCN36XX_HAL_MISSED_BEACON_IND nor WCN36XX_HAL_MISSED_BEACON_IND. It was noticed that such situation gets even more reproducible, when the driver fails to enter bmps mode - which is highly likely to occur. Thus, in order to provide proper disconnection of the connected STA, a disconnection timeout based on last time seen bss beacon is here given. Signed-off-by: Eduardo Abinader <eduardoabinader@xxxxxxxxx> --- drivers/net/wireless/ath/wcn36xx/txrx.c | 34 ++++++++++++++++++++++ drivers/net/wireless/ath/wcn36xx/txrx.h | 2 ++ drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 ++ 3 files changed, 38 insertions(+) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index a6902371e89c..98155b2115e0 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -23,11 +23,30 @@ static inline int get_rssi0(struct wcn36xx_rx_bd *bd) return 100 - ((bd->phy_stat0 >> 24) & 0xff); } +static inline void rx_check(struct timer_list *t) { + struct wcn36xx *wcn = from_timer(wcn, t, rx_timer); + struct ieee80211_vif *vif = NULL; + struct wcn36xx_vif *tmp; + + list_for_each_entry(tmp, &wcn->vif_list, list) { + vif = wcn36xx_priv_to_vif(tmp); + if (vif && vif->bss_conf.assoc) { + wcn36xx_warn("no beacons seen - disconnect timeout\n"); + + ieee80211_connection_loss(vif); + del_timer(&wcn->rx_timer); + wcn->rx_timer.function = NULL; + } + } +} + int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) { struct ieee80211_rx_status status; struct ieee80211_hdr *hdr; struct wcn36xx_rx_bd *bd; + struct ieee80211_vif *vif = NULL; + struct wcn36xx_vif *tmp; u16 fc, sn; /* @@ -77,6 +96,21 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) skb, skb->len, fc, sn); wcn36xx_dbg_dump(WCN36XX_DBG_BEACON_DUMP, "SKB <<< ", (char *)skb->data, skb->len); + + list_for_each_entry(tmp, &wcn->vif_list, list) { + vif = wcn36xx_priv_to_vif(tmp); + if (vif && vif->bss_conf.assoc && + ether_addr_equal(hdr->addr2, vif->bss_conf.bssid)) { + del_timer(&wcn->rx_timer); + wcn->rx_timer.function = NULL; + + wcn->rx_timer.expires = jiffies + + msecs_to_jiffies(RX_TIMEOUT); + timer_setup(&wcn->rx_timer, rx_check, 0); + add_timer(&wcn->rx_timer); + } + } + } else { wcn36xx_dbg(WCN36XX_DBG_RX, "rx skb %p len %d fc %04x sn %d\n", skb, skb->len, fc, sn); diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h index 032216e82b2b..f6b07cba165a 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.h +++ b/drivers/net/wireless/ath/wcn36xx/txrx.h @@ -32,6 +32,8 @@ #define WCN36XX_BD_RATE_MGMT 2 #define WCN36XX_BD_RATE_CTRL 3 +#define RX_TIMEOUT 30000 + enum wcn36xx_txbd_ssn_type { WCN36XX_TXBD_SSN_FILL_HOST = 0, WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS = 1, diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index a58f313983b9..a9cfb817fab7 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -254,6 +254,8 @@ struct wcn36xx { struct wcn36xx_dfs_entry dfs; #endif /* CONFIG_WCN36XX_DEBUGFS */ + struct timer_list rx_timer; + }; static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, -- 2.20.1