From 5b90ddb5cbf3281a36d1023f4ce17f8ec5820f91 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 2 Nov 2023 20:36:13 +0100 Subject: [PATCH] ioctl_cfg80211: Add support for standard RSSI notifications Currently background scanning with wpa_supplicant does not work very well because rtl8812au does not notify it about changes to RSSI. To fix this: * Implement the cfg80211_ops::set_cqm_rssi_config operation to set the parameters for RSSI notifications. * Add a rtw_cfg80211_cqm_rssi_update() function that calls cfg80211_cqm_rssi_notify() if the RSSI has changed significantly (based on those parameters). * When connected in infrastructure mode, call rtw_cfg80211_cqm_rssi_update() after processing a beacon and updating the RSSI. Signed-off-by: Ben Hutchings --- core/rtw_mlme_ext.c | 6 +++++ os_dep/linux/ioctl_cfg80211.c | 42 +++++++++++++++++++++++++++++++++++ os_dep/linux/ioctl_cfg80211.h | 7 ++++++ 3 files changed, 55 insertions(+) diff --git a/core/rtw_mlme_ext.c b/core/rtw_mlme_ext.c index 57e7536..527e06d 100644 --- a/core/rtw_mlme_ext.c +++ b/core/rtw_mlme_ext.c @@ -1971,6 +1971,12 @@ unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame) #if 0 /* move to validate_recv_mgnt_frame */ psta->sta_stats.rx_mgnt_pkts++; #endif + +#if defined(CONFIG_IOCTL_CFG80211) + rtw_cfg80211_cqm_rssi_update( + padapter, + pmlmepriv->cur_network_scanned->network.Rssi); +#endif } } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { diff --git a/os_dep/linux/ioctl_cfg80211.c b/os_dep/linux/ioctl_cfg80211.c index 0d96568..510fa45 100644 --- a/os_dep/linux/ioctl_cfg80211.c +++ b/os_dep/linux/ioctl_cfg80211.c @@ -4476,6 +4476,47 @@ static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, return 0; } +static int cfg80211_rtw_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *ndev, + s32 rssi_thold, u32 rssi_hyst) +{ + _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); + struct rtw_wdev_priv *priv = adapter_wdev_data(padapter); + + priv->cqm_rssi_thold = rssi_thold; + priv->cqm_rssi_hyst = rssi_hyst; + priv->cqm_rssi_last = 0; + + return 0; +} + +void rtw_cfg80211_cqm_rssi_update(_adapter *padapter, s32 rssi) +{ + struct rtw_wdev_priv *priv = adapter_wdev_data(padapter); + enum nl80211_cqm_rssi_threshold_event event; + + if (priv->cqm_rssi_thold == 0) + return; + + if (rssi < priv->cqm_rssi_thold && + (priv->cqm_rssi_last == 0 || + rssi < priv->cqm_rssi_last - priv->cqm_rssi_hyst)) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else if (rssi > priv->cqm_rssi_thold && + (priv->cqm_rssi_last == 0 || + rssi > priv->cqm_rssi_last + priv->cqm_rssi_hyst)) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + else + return; + + priv->cqm_rssi_last = rssi; + cfg80211_cqm_rssi_notify(padapter->pnetdev, event, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) + rssi, +#endif + GFP_ATOMIC); +} + #ifdef CONFIG_AP_MODE void rtw_cfg80211_indicate_sta_assoc(_adapter *padapter, u8 *pmgmt_frame, uint frame_len) { @@ -10157,6 +10198,7 @@ static struct cfg80211_ops rtw_cfg80211_ops = { .set_pmksa = cfg80211_rtw_set_pmksa, .del_pmksa = cfg80211_rtw_del_pmksa, .flush_pmksa = cfg80211_rtw_flush_pmksa, + .set_cqm_rssi_config = cfg80211_rtw_set_cqm_rssi_config, #ifdef RTW_VIRTUAL_INT .add_virtual_intf = cfg80211_rtw_add_virtual_intf, diff --git a/os_dep/linux/ioctl_cfg80211.h b/os_dep/linux/ioctl_cfg80211.h index e7dd805..d40a36e 100644 --- a/os_dep/linux/ioctl_cfg80211.h +++ b/os_dep/linux/ioctl_cfg80211.h @@ -185,6 +185,11 @@ struct rtw_wdev_priv { u16 pno_scan_seq_num; #endif + /* Standard RSSI notification parameters */ + s32 cqm_rssi_thold; + u32 cqm_rssi_hyst; + s32 cqm_rssi_last; + #ifdef CONFIG_RTW_CFGVEDNOR_RSSIMONITOR s8 rssi_monitor_max; s8 rssi_monitor_min; @@ -351,6 +356,8 @@ void rtw_cfg80211_init_rfkill(struct wiphy *wiphy); void rtw_cfg80211_deinit_rfkill(struct wiphy *wiphy); #endif +void rtw_cfg80211_cqm_rssi_update(_adapter *padapter, s32 rssi); + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE) #define rtw_cfg80211_rx_mgmt(wdev, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt(wdev_to_ndev(wdev), freq, buf, len, gfp) #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))