[PATCH wireless-next 4/7] wifi: mac80211: unshare the skb before building the header

Johannes Berg <[email protected]> Mon, 3 Aug 2026 16:08:40 +0200
Newsgroups org.kernel.vger.linux-wireless
Message-ID <[email protected]>
From: Johannes Berg <[email protected]>

ieee80211_build_hdr() unshares the skb halfway through, after it
has already looked at it but before it writes anything. That's not
a problem, but complicates the callers and requires passing the
flags to the function, etc.

Move the unsharing to the only caller that matters, the new one
from the previous patch has a fresh SKB and doesn't need it and
the TDLS callers via ieee80211_tdls_build_mgmt_packet_data() are
also fresh SKBs.

Signed-off-by: Johannes Berg <[email protected]>
---
 net/mac80211/tx.c | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 28c60ae442c0..1d139c2506bb 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2637,9 +2637,8 @@ static void ieee80211_remove_ack_skb(struct ieee80211_local *local, u16 info_id)
  * the appropriate IEEE 802.11 header based on which interface the packet is
  * being transmitted on.
  *
- * Note that this function also takes care of the TX status request and
- * potential unsharing of the SKB - this needs to be interleaved with the
- * header building.
+ * Note that this function also takes care of the TX status request. The skb
+ * must not be shared.
  *
  * The function requires the read-side RCU lock held
  *
@@ -2949,15 +2948,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
 		info_id = ieee80211_store_ack_skb(local, skb, &info_flags,
 						  cookie);
 
-	/*
-	 * If the skb is shared we need to obtain our own copy.
-	 */
-	skb = skb_share_check(skb, GFP_ATOMIC);
-	if (unlikely(!skb)) {
-		ret = -ENOMEM;
-		goto free;
-	}
-
 	hdr.frame_control = fc;
 	hdr.duration_id = 0;
 	hdr.seq_ctrl = 0;
@@ -4424,6 +4414,12 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 		if (skb->protocol == sdata->control_port_protocol)
 			ctrl_flags |= IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP;
 
+		skb = skb_share_check(skb, GFP_ATOMIC);
+		if (unlikely(!skb)) {
+			kfree_skb_list(next);
+			goto out;
+		}
+
 		skb = ieee80211_build_hdr(sdata, skb, info_flags,
 					  sta, ctrl_flags, 0);
 		if (IS_ERR(skb)) {
-- 
2.55.0