git: 56a4abe124de - stable/14 - llan: byte swap the receive queue entries

From: Piotr Kubaj <pkubaj_at_FreeBSD.org>
Date: Thu, 01 Oct 2026 06:10:53 UTC
The branch stable/14 has been updated by pkubaj:

URL: https://cgit.FreeBSD.org/src/commit/?id=56a4abe124de6baf9ba1004893651ec210fa2a3e

commit 56a4abe124de6baf9ba1004893651ec210fa2a3e
Author:     Piotr Kubaj <pkubaj@FreeBSD.org>
AuthorDate: 2026-09-23 13:21:00 +0000
Commit:     Piotr Kubaj <pkubaj@FreeBSD.org>
CommitDate: 2026-10-01 05:54:45 +0000

    llan: byte swap the receive queue entries
    
    The receive queue of a PAPR logical LAN is filled in by the hypervisor, so
    its fields are big endian, but llan_intr() read the offset and the length of
    each frame natively.  On a little endian kernel the length of a 134 byte
    frame reads as 0x86000000, and ether_input() discards the mbuf because m_len
    is not even large enough for an ethernet header.  No frame is ever received.
    
    Reproduced on a POWER9 pseries guest with a spapr-vlan interface.  Before:
    
      llan0: discard frame w/o leading ethernet header (len -2046820352
          pkt len -2046820352)
      llan0 1500 <Link#1> 52:54:00:12:34:56  123  118  0  5838733312  7  0
    
    that is 118 input errors out of 123 packets, dhclient(8) never completes and
    ping(8) loses every packet, although transmit works because the transmit
    path passes the lengths in hcall registers rather than through memory.
    Afterwards the interface gets a DHCP lease and ping reports no loss.
    
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D59926
    Approved by:    jhibbits
    
    (cherry picked from commit 6429199a21136cad3c82b43618a6ca2958b90bbf)
    (cherry picked from commit d8cbdc3b09d0196e2f23a2e1f934fa0811eb28b7)
---
 sys/powerpc/pseries/phyp_llan.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/powerpc/pseries/phyp_llan.c b/sys/powerpc/pseries/phyp_llan.c
index 5da5fd78fcc3..9e33781947b8 100644
--- a/sys/powerpc/pseries/phyp_llan.c
+++ b/sys/powerpc/pseries/phyp_llan.c
@@ -386,8 +386,8 @@ restart:
 	while ((sc->rx_buf[sc->rx_dma_slot].control >> 7) == sc->rx_valid_val) {
 		rx = (struct llan_xfer *)sc->rx_buf[sc->rx_dma_slot].handle;
 		m = rx->rx_mbuf;
-		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset - 8);
-		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
+		m_adj(m, be16toh(sc->rx_buf[sc->rx_dma_slot].offset) - 8);
+		m->m_len = be32toh(sc->rx_buf[sc->rx_dma_slot].length);
 
 		/* llan_add_rxbuf does DMA sync and unload as well as requeue */
 		if (llan_add_rxbuf(sc, rx) != 0) {
@@ -396,8 +396,8 @@ restart:
 		}
 
 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
-		m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset);
-		m->m_len = sc->rx_buf[sc->rx_dma_slot].length;
+		m_adj(m, be16toh(sc->rx_buf[sc->rx_dma_slot].offset));
+		m->m_len = be32toh(sc->rx_buf[sc->rx_dma_slot].length);
 		m->m_pkthdr.rcvif = sc->ifp;
 		m->m_pkthdr.len = m->m_len;
 		sc->rx_dma_slot++;