]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: Add multicast to unicast support for 802.3 path
authorTamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Thu, 4 Jun 2026 16:24:02 +0000 (21:54 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 5 Jun 2026 14:09:04 +0000 (16:09 +0200)
mac80211 already supports multicast-to-unicast conversion for
native 802.11 TX paths, but this handling is missing for the
802.3 transmit path. Due to that the packet never converted to
unicast and directly pass it to 802.11 Tx path by checking the
destination address as multicast.

Extend ieee80211_subif_start_xmit_8023() to honor the
multicast_to_unicast setting by cloning and converting multicast
Ethernet frames into per-station unicast transmissions, following
the same behavior of the native 802.11 TX path and allow it
to take 802.3 path.

Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Link: https://patch.msgid.link/20260604162403.1563729-3-tamizh.raja@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/tx.c

index 15ec77255c3f5d30ca548885f800dc6210ba437c..a353758f53ff2c66f8db3efc612242282a348f37 100644 (file)
@@ -4746,19 +4746,14 @@ out_free:
        kfree_skb(skb);
 }
 
-netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
-                                           struct net_device *dev)
+static void __ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
+                                             struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ethhdr *ehdr = (struct ethhdr *)skb->data;
        struct ieee80211_key *key;
        struct sta_info *sta;
 
-       if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
        rcu_read_lock();
 
        if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
@@ -4787,6 +4782,30 @@ skip_offload:
        ieee80211_subif_start_xmit(skb, dev);
 out:
        rcu_read_unlock();
+}
+
+netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
+                                           struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ethhdr *ehdr = (struct ethhdr *)skb->data;
+
+       if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (unlikely(is_multicast_ether_addr(ehdr->h_dest) &&
+                    ieee80211_multicast_to_unicast(skb, dev))) {
+               struct sk_buff_head queue;
+
+               __skb_queue_head_init(&queue);
+               ieee80211_convert_to_unicast(skb, dev, &queue);
+               while ((skb = __skb_dequeue(&queue)))
+                       __ieee80211_subif_start_xmit_8023(skb, dev);
+       } else {
+               __ieee80211_subif_start_xmit_8023(skb, dev);
+       }
 
        return NETDEV_TX_OK;
 }