blob: b7c620f20e52cc997d4a16a8cddfc864efe4b2c1 [file] [log] [blame]
From 184ecc9c9c16bbc9b93a69c994194d8bf1e41e72 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Tue, 20 Feb 2024 10:08:01 +0800
Subject: [PATCH 109/116] wifi: mt76: mt7996: add beacon monitoring in driver
for mlo
Add beacon monitoring in driver since mac80211 does not
support connect monitoring if WIPHY_FLAG_SUPPORTS_MLO is set.
(IEEE80211_HW_CONNECTION_MONITOR should be set)
CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: I52211987abd6309bbb23dc648af3f377adf8982a
---
mt7996/mac.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
mt7996/main.c | 50 +++++++++++++++++++++++++++++++++++++++++++
mt7996/mt7996.h | 7 +++++++
3 files changed, 113 insertions(+)
diff --git a/mt7996/mac.c b/mt7996/mac.c
index 5967b6aeb..2a45fc03d 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -565,6 +565,21 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
*/
if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
*qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ } else if (ieee80211_is_beacon(fc)) {
+ struct ieee80211_hw *hw = phy->mt76->hw;
+ struct ieee80211_sta *sta;
+ struct mt7996_sta *msta;
+ unsigned int link_id;
+
+ sta = ieee80211_find_sta_by_link_addrs(hw, hdr->addr2, NULL, &link_id);
+ if (!sta)
+ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
+
+ if (sta) {
+ msta = (struct mt7996_sta *)sta->drv_priv;
+ if (msta && msta->vif)
+ msta->vif->beacon_received_time[band_idx] = jiffies;
+ }
}
#ifdef CONFIG_MTK_VENDOR
if (phy->amnt_ctrl.enable && !ieee80211_is_beacon(fc))
@@ -2956,6 +2971,47 @@ void mt7996_scan_work(struct work_struct *work)
ieee80211_queue_delayed_work(hw, &phy->scan_work, duration);
}
+void mt7996_beacon_mon_work(struct work_struct *work)
+{
+ struct mt7996_vif *mvif = container_of(work, struct mt7996_vif, beacon_mon_work.work);
+ struct ieee80211_vif *vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
+ struct ieee80211_hw *hw = mvif->hw;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ unsigned long next_time = ULONG_MAX, valid_links = vif->valid_links ?: BIT(0);
+ unsigned int link_id;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct ieee80211_bss_conf *conf;
+ struct mt7996_bss_conf *mconf;
+ struct mt7996_phy *phy;
+ unsigned long timeout, loss_duration;
+
+ conf = link_conf_dereference_protected(vif, link_id);
+ mconf = mconf_dereference_protected(mvif, link_id);
+ if (!conf || !mconf)
+ continue;
+
+ phy = mconf->phy;
+ loss_duration = msecs_to_jiffies(MT7996_MAX_BEACON_LOSS * conf->beacon_int);
+ timeout = mvif->beacon_received_time[phy->mt76->band_idx] + loss_duration;
+ if (time_after_eq(jiffies, timeout)) {
+ mutex_unlock(&dev->mt76.mutex);
+ wiphy_info(hw->wiphy,
+ "link %d: detected beacon loss, start disconnecting\n",
+ link_id);
+ /* TODO: disconnect single link & handle link reconfiguration for MLD */
+ ieee80211_connection_loss(vif);
+ return;
+ }
+ next_time = min(next_time, timeout - jiffies);
+ }
+ mutex_unlock(&dev->mt76.mutex);
+
+ ieee80211_queue_delayed_work(hw, &mvif->beacon_mon_work, next_time);
+}
+
void mt7996_get_hw(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 phy_idx,
struct ieee80211_hw **hw)
{
diff --git a/mt7996/main.c b/mt7996/main.c
index 6943b28ba..e37f0c013 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -450,6 +450,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
is_zero_ether_addr(vif->addr))
phy->monitor_vif = vif;
+ INIT_DELAYED_WORK(&mvif->beacon_mon_work, mt7996_beacon_mon_work);
mvif->dev = dev;
mvif->hw = hw;
mvif->sta.vif = mvif;
@@ -2565,6 +2566,54 @@ out:
return ret;
}
+static void
+mt7996_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ switch (event->type) {
+ case MLME_EVENT:
+ if (event->u.mlme.data == ASSOC_EVENT &&
+ event->u.mlme.status == MLME_SUCCESS) {
+ struct ieee80211_bss_conf *conf;
+ struct mt7996_bss_conf *mconf;
+ struct mt7996_phy *phy;
+ unsigned long cur, valid_links = vif->valid_links ?: BIT(0);
+ unsigned int link_id;
+ int next_time = INT_MAX;
+
+ cur = jiffies;
+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ conf = link_conf_dereference_protected(vif, link_id);
+ mconf = mconf_dereference_protected(mvif, link_id);
+ if (conf && mconf) {
+ phy = mconf->phy;
+ mvif->beacon_received_time[phy->mt76->band_idx] = cur;
+ next_time = min(next_time,
+ MT7996_MAX_BEACON_LOSS *
+ conf->beacon_int);
+ }
+ }
+
+ ieee80211_queue_delayed_work(hw, &mvif->beacon_mon_work,
+ msecs_to_jiffies(next_time));
+ break;
+ }
+
+ cancel_delayed_work_sync(&mvif->beacon_mon_work);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&dev->mt76.mutex);
+ return;
+}
+
const struct ieee80211_ops mt7996_ops = {
.tx = mt7996_tx,
.start = mt7996_start,
@@ -2617,6 +2666,7 @@ const struct ieee80211_ops mt7996_ops = {
.net_fill_forward_path = mt7996_net_fill_forward_path,
.net_setup_tc = mt76_wed_net_setup_tc,
#endif
+ .event_callback = mt7996_event_callback,
.add_chanctx = mt7996_add_chanctx,
.remove_chanctx = mt7996_remove_chanctx,
.change_chanctx = mt7996_change_chanctx,
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index dc3cacc3a..0412d7375 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -128,6 +128,8 @@
#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
+#define MT7996_MAX_BEACON_LOSS 50
+
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
@@ -360,6 +362,10 @@ struct mt7996_vif {
u8 mld_remap_id;
u8 band_to_link[__MT_MAX_BAND];
+
+ /* for beacon monitoring */
+ struct delayed_work beacon_mon_work;
+ unsigned long beacon_received_time[__MT_MAX_BAND];
};
/* crash-dump */
@@ -1113,6 +1119,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
void mt7996_stats_work(struct work_struct *work);
void mt7996_scan_work(struct work_struct *work);
void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted);
+void mt7996_beacon_mon_work(struct work_struct *work);
int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);
void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy);
--
2.39.2