summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/rx.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9f1ea8c840e9..cad4b2378218 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4724,6 +4724,9 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
{
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct link_sta_info *link_sta = NULL;
+ struct ieee80211_link_data *link;
rx->skb = skb;
@@ -4745,6 +4748,15 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
if (!ieee80211_accept_frame(rx))
return false;
+ if (unlikely(!is_multicast_ether_addr(hdr->addr1) &&
+ rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) {
+ link_sta = rcu_dereference(rx->sta->link[rx->link_id]);
+ link = rcu_dereference(rx->sdata->link[rx->link_id]);
+
+ if (WARN_ON_ONCE(!link_sta || !link))
+ return true;
+ }
+
if (!consume) {
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) {
@@ -4758,6 +4770,19 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
rx->skb = skb;
}
+ if (unlikely(link_sta)) {
+ /* translate to MLD addresses */
+ if (ether_addr_equal(link->conf->addr, hdr->addr1))
+ ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
+ if (ether_addr_equal(link_sta->addr, hdr->addr2))
+ ether_addr_copy(hdr->addr2, rx->sta->addr);
+ if (ether_addr_equal(link_sta->addr, hdr->addr3))
+ ether_addr_copy(hdr->addr3, rx->sta->addr);
+ else if (ether_addr_equal(link->conf->addr, hdr->addr3))
+ ether_addr_copy(hdr->addr3, rx->sdata->vif.addr);
+ /* not needed for A4 since it can only carry the SA */
+ }
+
ieee80211_invoke_rx_handlers(rx);
return true;
}