[PATCH v4 3/8] wifi: brcmfmac: core: fix missing headroom check and populate radiotap RSSI

From: Shivesh

Date: Fri Jul 31 2026 - 12:22:36 EST


Two problems exist in brcmf_netif_mon_rx():

1. skb_push() is called without first verifying that the skb has
sufficient headroom. If the skb arrives with zero headroom the
kernel will panic. Use skb_cow_head() before each skb_push() and
free the skb on allocation failure.

2. When the firmware provides a hardware RX header
(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR), the driver strips it and
inserts a blank ieee80211_radiotap_header with no signal data.
Monitor-mode packet captures therefore show no signal strength,
making tools like Wireshark and iw unable to report RSSI.

Define struct brcmf_radiotap_info that embeds the standard radiotap
header followed by a dbm_antsignal field. Extract the rssi value from
wlc_d11rxhdr and populate it_present with
IEEE80211_RADIOTAP_DBM_ANTSIGNAL so userspace tools can read signal
strength from monitor-mode frames.

Also replace the open-coded "skb->len -= 4" with skb_trim(), which
is the correct API for shortening a linear skb.

Fixes: e665988be29c ("brcmfmac: support monitor frames with the hardware/ucode header")
Signed-off-by: Shivesh <chanelshivesh@xxxxxxxxx>
---
.../broadcom/brcm80211/brcmfmac/core.c | 44 ++++++++++++-------
1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index ec170647800d..eefc437dd055 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -431,45 +431,55 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
netif_rx(skb);
}

+struct brcmf_radiotap_info {
+ struct ieee80211_radiotap_header hdr;
+ s8 dbm_antsignal;
+} __packed;
+
void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
{
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_RADIOTAP)) {
- /* Do nothing */
+ /* Firmware already provided a full radiotap header; do nothing */
} else if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR)) {
struct wlc_d11rxhdr *wlc_rxhdr = (struct wlc_d11rxhdr *)skb->data;
- struct ieee80211_radiotap_header *radiotap;
+ struct brcmf_radiotap_info *rtap;
unsigned int offset;
u16 RxStatus1;
+ s8 rssi;

RxStatus1 = le16_to_cpu(wlc_rxhdr->rxhdr.RxStatus1);
+ rssi = wlc_rxhdr->rssi;

offset = sizeof(struct wlc_d11rxhdr);
- /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU
- * subframes
- */
+ /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
if (RxStatus1 & RXS_PBPRES)
offset += 2;
offset += D11_PHY_HDR_LEN;

skb_pull(skb, offset);

- /* TODO: use RX header to fill some radiotap data */
- radiotap = skb_push(skb, sizeof(*radiotap));
- memset(radiotap, 0, sizeof(*radiotap));
- radiotap->it_len = cpu_to_le16(sizeof(*radiotap));
-
- /* TODO: 4 bytes with receive status? */
- skb->len -= 4;
+ /* Insert our radiotap header with RSSI data */
+ if (skb_cow_head(skb, sizeof(*rtap)))
+ goto drop;
+ rtap = skb_push(skb, sizeof(*rtap));
+ memset(rtap, 0, sizeof(*rtap));
+ rtap->hdr.it_len = cpu_to_le16(sizeof(*rtap));
+ rtap->hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
+ rtap->dbm_antsignal = rssi;
+
+ /* Strip the 4-byte receive status / FCS tail */
+ skb_trim(skb, skb->len - 4);
} else {
struct ieee80211_radiotap_header *radiotap;

- /* TODO: use RX status to fill some radiotap data */
+ if (skb_cow_head(skb, sizeof(*radiotap)))
+ goto drop;
radiotap = skb_push(skb, sizeof(*radiotap));
memset(radiotap, 0, sizeof(*radiotap));
radiotap->it_len = cpu_to_le16(sizeof(*radiotap));

- /* TODO: 4 bytes with receive status? */
- skb->len -= 4;
+ /* Strip the 4-byte receive status / FCS tail */
+ skb_trim(skb, skb->len - 4);
}

skb->dev = ifp->ndev;
@@ -478,6 +488,10 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
skb->protocol = htons(ETH_P_802_2);

brcmf_netif_rx(ifp, skb);
+ return;
+
+drop:
+ brcmu_pkt_buf_free_skb(skb);
}

static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
--
2.53.0