From: CicadaTAK Date: Thu, 22 Oct 2026 00:00:00 +0000 Subject: [PATCH] batman-adv: mcast: keep skb->data aligned when expanding headroom CicadaTAK-Marker: CICADATAK-BATADV-M1 batadv_mcast_forw_expand_head() grows the headroom by exactly 1298 - skb->len (VLAN_ETH_HLEN + IPV6_MIN_MTU - len). pskb_expand_head() moves skb->data by nhead, so the data pointer's alignment shifts by an amount with the parity of the packet's length: an odd-length multicast packet leaves batman with skb->data on an odd address. Every other batman path grows headroom through skb_cow_head(), which rounds to NET_SKB_PAD and keeps the alignment. The Morse MM6108 HaLow driver then tells the chip an odd frame offset (morse_driver skbq.c, bulk_alignment 2 on SPI) and the frame is never delivered: CicadaTAK measured every odd-length batman MCAST frame lost on HaLow and every even one delivered (0/56 vs 56/56, 2026-10-22), while UNICAST and BCAST, which keep their alignment, pass at both parities. Round the growth up to NET_SKB_PAD, as __skb_cow() does. The headroom only grows (by at most NET_SKB_PAD - 1 more bytes); nothing else changes. cicadatak_mcast_align is a 0644 module parameter (default Y); N restores the stock growth at runtime. Plan: cicadatak.git docs/plans/batman-mcast-align.md. --- --- a/net/batman-adv/multicast_forw.c +++ b/net/batman-adv/multicast_forw.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -1073,6 +1075,19 @@ sizeof(struct batadv_mcast_packet); } +/* CicadaTAK (CICADATAK-BATADV-M1): grow the headroom in NET_SKB_PAD steps, as + * __skb_cow() does, so that skb->data keeps its alignment. The stock growth, + * 1298 - skb->len, has the parity of the packet's length, so it leaves an + * odd-length packet's data on an odd address; the Morse MM6108 HaLow chip + * then never delivers it (cicadatak.git docs/plans/batman-mcast-align.md). + * N restores the stock growth at runtime. + */ +static bool cicadatak_mcast_align = true; +module_param(cicadatak_mcast_align, bool, 0644); +MODULE_PARM_DESC(cicadatak_mcast_align, + "Grow MCAST headroom in NET_SKB_PAD steps to keep skb->data aligned (default Y; N = stock)"); +MODULE_INFO(cicadatak, "CICADATAK-BATADV-M1"); + /** * batadv_mcast_forw_expand_head() - expand headroom for an mcast packet * @bat_priv: the bat priv with all the soft interface information @@ -1102,7 +1117,9 @@ } if (skb_headroom(skb) < hdr_size && - pskb_expand_head(skb, hdr_size, 0, GFP_ATOMIC) < 0) + pskb_expand_head(skb, READ_ONCE(cicadatak_mcast_align) ? + ALIGN(hdr_size, NET_SKB_PAD) : hdr_size, + 0, GFP_ATOMIC) < 0) return -ENOMEM; return 0;