wifi: mac80211: implement MLO multicast deduplication
authorJohannes Berg <johannes.berg@intel.com>
Mon, 29 Jan 2024 19:04:57 +0000 (20:04 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 8 Feb 2024 14:00:42 +0000 (15:00 +0100)
If the vif is an MLD then it may receive multicast from
different links, and should drop those frames according
to the SN. Implement that.

Link: https://msgid.link/20240129200456.693b77d14b44.I491846f2bea0058c14eab6422962c10bfae9b675@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/linux/ieee80211.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rx.c

index b9367d5f04c4d91ba73b0edae2386009a9bc9471..e9078143b822f03ae742b3006cad02eb696f6c07 100644 (file)
@@ -191,6 +191,11 @@ static inline bool ieee80211_sn_less(u16 sn1, u16 sn2)
        return ((sn1 - sn2) & IEEE80211_SN_MASK) > (IEEE80211_SN_MODULO >> 1);
 }
 
+static inline bool ieee80211_sn_less_eq(u16 sn1, u16 sn2)
+{
+       return ((sn2 - sn1) & IEEE80211_SN_MASK) <= (IEEE80211_SN_MODULO >> 1);
+}
+
 static inline u16 ieee80211_sn_add(u16 sn1, u16 sn2)
 {
        return (sn1 + sn2) & IEEE80211_SN_MASK;
index 534cac3fc8dfa0032f62be8a142aff04bdee99e5..46b517cf47ea6841a539c514ae3c6bc829c67aac 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2015  Intel Mobile Communications GmbH
- * Copyright (C) 2018-2022 Intel Corporation
+ * Copyright (C) 2018-2024 Intel Corporation
  */
 
 #ifndef IEEE80211_I_H
@@ -523,6 +523,8 @@ struct ieee80211_if_managed {
 
        unsigned int flags;
 
+       u16 mcast_seq_last;
+
        bool status_acked;
        bool status_received;
        __le16 status_fc;
index 4eaf5c10efdb44a398a28fd3bd746b135004e988..35dda59828540b659c24395bd058a42a2415a987 100644 (file)
@@ -3351,6 +3351,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
                                  &ifmgd->neg_ttlm_timeout_work);
        ieee80211_vif_set_links(sdata, 0, 0);
+
+       ifmgd->mcast_seq_last = IEEE80211_SN_MODULO;
 }
 
 static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
@@ -7512,6 +7514,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
        spin_lock_init(&ifmgd->teardown_lock);
        ifmgd->teardown_skb = NULL;
        ifmgd->orig_teardown_skb = NULL;
+       ifmgd->mcast_seq_last = IEEE80211_SN_MODULO;
 }
 
 static void ieee80211_recalc_smps_work(struct wiphy *wiphy,
index 53c4764dc1ed8b9f0269ad9a7cbe569bbe12015a..9902ea69af0a18fc785319916ac24af687d6d39d 100644 (file)
@@ -1434,13 +1434,31 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
                return RX_CONTINUE;
 
        if (ieee80211_is_ctl(hdr->frame_control) ||
-           ieee80211_is_any_nullfunc(hdr->frame_control) ||
-           is_multicast_ether_addr(hdr->addr1))
+           ieee80211_is_any_nullfunc(hdr->frame_control))
                return RX_CONTINUE;
 
        if (!rx->sta)
                return RX_CONTINUE;
 
+       if (unlikely(is_multicast_ether_addr(hdr->addr1))) {
+               struct ieee80211_sub_if_data *sdata = rx->sdata;
+               u16 sn = ieee80211_get_sn(hdr);
+
+               if (!ieee80211_is_data_present(hdr->frame_control))
+                       return RX_CONTINUE;
+
+               if (!ieee80211_vif_is_mld(&sdata->vif) ||
+                   sdata->vif.type != NL80211_IFTYPE_STATION)
+                       return RX_CONTINUE;
+
+               if (sdata->u.mgd.mcast_seq_last != IEEE80211_SN_MODULO &&
+                   ieee80211_sn_less_eq(sn, sdata->u.mgd.mcast_seq_last))
+                       return RX_DROP_U_DUP;
+
+               sdata->u.mgd.mcast_seq_last = sn;
+               return RX_CONTINUE;
+       }
+
        if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                     rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) {
                I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);