/*
 * DF-4266 PoC rig — inverted RX descriptor-ownership test in wb_rxeof()
 * (sys/dev/netif/wb/if_wb.c:972-975).
 *
 *   production loop:  rxstat = head->wb_ptr->wb_status;
 *                     if ((rxstat & WB_RXSTAT_OWN) == 0)   <-- INVERTED
 *                             break;
 *
 * The W89C840F sets OWN=1 when the DRIVER arms a descriptor (wb_newbuf
 * arms with WB_RXSTAT = FIRSTFRAG|LASTFRAG|OWN, if_wbreg.h:243) and
 * clears OWN on write-back when a frame completes.  The loop above
 * therefore (a) BREAKS on completed frames — RX is dead, ipackets stays
 * 0 forever — and (b) PROCESSES chip-owned descriptors.
 *
 * THE REAL PRODUCTION HANDLERS ARE DISPATCHED.  The guest kernel is
 * built with `device wb` (X86_64_GENERIC:246), so the driver's static
 * wb_rxeof()/wb_init()/wb_stop() exist in the running kernel image
 * (/boot/kernel/kernel).  Their addresses are resolved with nm(1) and
 * injected into this KLD through sysctls; the rig then calls THE
 * KERNEL'S OWN CODE — nothing about the handler under test is
 * recompiled, copied or modified here.  (wb_newbuf exists in the image
 * only as an IPA-SRA clone `wb_newbuf.isra.5' with a compiler-mangled
 * ABI — deliberately NOT resolved; the ring is armed by dispatching the
 * kernel's own wb_init(), whose inlined wb_list_rx_init/wb_newbuf build
 * the exact production post-init state.)
 *
 * The rig reconstructs the post-attach driver state:
 *   - struct wb_softc + struct wb_list_data in module .bss (never
 *     freed — no teardown UAF surface; module unload drops them),
 *   - wb_ldata armed by the REAL wb_init(): 64 MGETHDR mbufs hung on
 *     the ring exactly as wb_list_rx_init does, descriptors all
 *     WB_RXSTAT (chip-owned),
 *   - a fake miibus device_t whose softc is a zeroed mii_data (empty
 *     phys list: mii_mediachg/mii_pollstat/mii_tick degenerate to no-ops
 *     — wb_init/wb_reset/wb_fixmedia run their full real bodies safely),
 *   - a real lwkt serializer as ifp->if_serializer (production: wb_intr
 *     runs wb_rxeof under it),
 *   - a scratch page standing in for the MMIO BAR so CSR_* lands
 *     harmlessly (a plain page keeps WB_BUSCTL_RESET latched: wb_reset's
 *     1000xDELAY(10) poll runs out and prints "reset never completed!"
 *     once per reset — a rig artifact, ~10 ms; real HW clears the bit).
 * The "NIC" is simulated the only way the driver can observe it:
 * descriptor status/buffer writes.
 *
 * Scenarios (all dispatch the REAL kernel wb_rxeof unless noted):
 *   S1    chip COMPLETED a frame in slot 0 (write-back: OWN=0, RXCMP
 *         set, len 64 incl CRC) -> the loop breaks at once: 0 frames
 *         delivered, ipackets 0, descriptor NOT re-armed, head NOT
 *         advanced.  RX is dead.  (THE finding.)
 *   S1fix the IDENTICAL state handed to a one-line-fixed comparator
 *         (verbatim transcription of wb_rxeof with only
 *         `if ((rxstat & WB_RXSTAT_OWN) == 0) break;' ->
 *          `if (rxstat & WB_RXSTAT_OWN) break;'  — fix.diff):
 *         1 frame delivered, slot re-armed — proves the state was
 *         processable and only the inverted test blocks it.
 *   S2    armed idle ring (all descriptors OWN=1, exactly what
 *         wb_init/wb_newbuf leave) -> each dispatch PROCESSES a
 *         chip-owned descriptor: head popped, ierrors++, "receiver
 *         babbling", wb_fixmedia + wb_reset + wb_init (full 64-mbuf
 *         ring teardown/re-init) PER dispatch.  In production every
 *         RX_NOBUF/RX_OK interrupt pays this (wb_intr:1137-1144,1146):
 *         unauthenticated adjacent-frame-triggered permanent reset
 *         storm with 100% RX loss.
 *   S3    descriptor STILL chip-owned (OWN=1) but looking complete —
 *         the mid-write-back transient the inverted loop wrongly
 *         accepts -> frame ACCEPTED from a chip-owned descriptor and
 *         the descriptor RE-ARMED (status/data rewritten) under the
 *         chip: ownership protocol broken end-to-end.
 *
 * Usage (root):
 *   kldload ./df4266_wb_poc.ko
 *   sysctl -w kern.df4266.rxeof=0x$(nm /boot/kernel/kernel | awk '/ t wb_rxeof$/{print $1}')
 *   sysctl -w kern.df4266.init=0x$(nm  /boot/kernel/kernel | awk '/ t wb_init$/{print $1}')
 *   sysctl -w kern.df4266.stop=0x$(nm  /boot/kernel/kernel | awk '/ t wb_stop$/{print $1}')
 *   sysctl -w kern.df4266.go=1
 *
 * Expected on stock /usr/src: "S1 BUG CONFIRMED", "S1fix ... 1 FRAME
 *   DELIVERED", "S2 BUG CONFIRMED" (3x babbling + per-dispatch ring
 *   re-init), "S3 BUG CONFIRMED", SURVIVED.
 * Expected on fix.diff-patched kernel (fix validation run): S1 delivers
 *   via the REAL handler; S2/S3 break on OWN-set descriptors; no bug
 *   markers.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/serialize.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/callout.h>

#include <sys/bus.h>
#include <sys/bus_private.h>	/* struct bsd_device: fake miibus stand-in */
#include <machine/bus_dma.h>	/* X86_64_BUS_SPACE_MEM */

#include <vm/vm.h>
#include <vm/pmap.h>		/* vtophys */

#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_var.h>
#include <net/ifq_var.h>
#include <net/if_media.h>
#include <net/ethernet.h>

#include <dev/netif/mii_layer/mii.h>
#include <dev/netif/mii_layer/miivar.h>

#include <dev/netif/wb/if_wbreg.h>

/* ------------------------------------------------------------------ */
/* REAL kernel handlers, resolved from /boot/kernel/kernel via nm(1)   */
/* ------------------------------------------------------------------ */
static void (*p_wb_rxeof)(struct wb_softc *);
static void (*p_wb_init)(void *);
static void (*p_wb_stop)(struct wb_softc *);

static int df_ran;

SYSCTL_NODE(_kern, OID_AUTO, df4266, CTLFLAG_RW, 0, "DF-4266 PoC rig");

/*
 * Address-injection sysctls take hex STRINGS ("ffffffff808dae30"):
 * sysctl_handle_int/long clamp values above INT64_MAX, which is where
 * every static-kernel address lives on x86_64.
 */
static int
df_sysctl_addr(SYSCTL_HANDLER_ARGS, void **target)
{
	char buf[32];
	const char *s;
	int error, len;

	ksnprintf(buf, sizeof(buf), "0x%016llx",
	    (unsigned long long)(uintptr_t)*target);
	error = SYSCTL_OUT(req, buf, strlen(buf) + 1);
	if (error || req->newptr == NULL)
		return (error);
	len = req->newlen - req->newidx;
	if (len >= (int)sizeof(buf))
		return (EINVAL);
	error = SYSCTL_IN(req, buf, len);
	if (error)
		return (error);
	buf[len] = '\0';
	s = buf;
	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
		s += 2;
	*target = (void *)(uintptr_t)strtoul(s, NULL, 16);
	return (0);
}

#define DF_ADDR_SYSCTL(name, var, descr)				\
static int								\
df_sysctl_##name(SYSCTL_HANDLER_ARGS)					\
{									\
	return (df_sysctl_addr(oidp, arg1, arg2, req, (void **)&var));	\
}									\
SYSCTL_PROC(_kern_df4266, OID_AUTO, name,				\
    CTLTYPE_STRING | CTLFLAG_RW, NULL, 0, df_sysctl_##name, "A", descr);

DF_ADDR_SYSCTL(rxeof, p_wb_rxeof, "kernel address of static wb_rxeof() (hex)")
DF_ADDR_SYSCTL(init,  p_wb_init,  "kernel address of static wb_init() (hex)")
DF_ADDR_SYSCTL(stop,  p_wb_stop,  "kernel address of static wb_stop() (hex)")

/* ------------------------------------------------------------------ */
/* Static rig state — module .bss, never freed (no teardown UAF)       */
/* ------------------------------------------------------------------ */
static struct wb_softc df_sc;
static struct wb_list_data df_ldata;
static struct mii_data df_mii;			/* zeroed: empty phys list */
static struct bsd_device df_miibus_dev;	/* .softc = &df_mii */
static uint32_t df_mmio[PAGE_SIZE / 4]
    __attribute__((__aligned__(PAGE_SIZE)));	/* MMIO BAR stand-in */
static struct lwkt_serialize df_ser;
static struct ifdata_pcpu df_ifdata[64];
static struct ifaltq_subque df_subq __attribute__((__aligned__(64)));

static int df_delivered;			/* if_input sink counter */

static u_long
df_stat(size_t off)
{
	u_long v = 0;
	int i;

	for (i = 0; i < 64; i++)
		v += *(u_long *)((char *)&df_ifdata[i] + off);
	return (v);
}
#define DF_STAT(f)	df_stat(__offsetof(struct ifdata_pcpu, f))

/*
 * Production if_input stand-in (ether_input/netisr in the real stack):
 * record and describe the delivered chain, then consume it exactly as
 * the network stack eventually would.
 */
static void
df_input(struct ifnet *ifp, struct mbuf *m, const struct pktinfo *pi,
    int cpuid)
{
	uint8_t *p = mtod(m, uint8_t *);

	if (m->m_len >= 18) {
		kprintf("df4266: if_input: m=%p m_len=%d "
		    "dst=%02x:%02x:%02x:%02x:%02x:%02x "
		    "src=%02x:%02x:%02x:%02x:%02x:%02x type=%02x%02x "
		    "pay=%02x %02x %02x %02x\n",
		    m, m->m_len,
		    p[0], p[1], p[2], p[3], p[4], p[5],
		    p[6], p[7], p[8], p[9], p[10], p[11],
		    p[12], p[13], p[14], p[15], p[16], p[17]);
	} else {
		kprintf("df4266: if_input: m=%p m_len=%d\n", m, m->m_len);
	}
	df_delivered++;
	m_freem(m);
}

/* ================================================================== */
/* ONE-LINE-FIXED COMPARATOR — verbatim transcription of the guest's  */
/* /usr/src/sys/dev/netif/wb/if_wb.c wb_rxeof()/wb_newbuf()/wb_bfree  */
/* with EXACTLY ONE change (the fix.diff line, marked FIX below).     */
/* This is NOT the code under test — it is the counterfactual.        */
/* ================================================================== */
static void
df_wb_bfree(void *arg)
{
}

static int
df_wb_newbuf(struct wb_softc *sc, struct wb_chain_onefrag *c, struct mbuf *m)
{
	struct mbuf *m_new = NULL;

	if (m == NULL) {
		MGETHDR(m_new, M_NOWAIT, MT_DATA);
		if (m_new == NULL)
			return(ENOBUFS);

		m_new->m_data = m_new->m_ext.ext_buf = c->wb_buf;
		m_new->m_flags |= M_EXT;
		m_new->m_ext.ext_size = m_new->m_pkthdr.len =
		    m_new->m_len = WB_BUFBYTES;
		m_new->m_ext.ext_free = df_wb_bfree;
		m_new->m_ext.ext_ref = df_wb_bfree;
	} else {
		m_new = m;
		m_new->m_len = m_new->m_pkthdr.len = WB_BUFBYTES;
		m_new->m_data = m_new->m_ext.ext_buf;
	}

	m_adj(m_new, sizeof(uint64_t));

	c->wb_mbuf = m_new;
	c->wb_ptr->wb_data = vtophys(mtod(m_new, caddr_t));
	c->wb_ptr->wb_ctl = WB_RXCTL_RLINK | 1536;
	c->wb_ptr->wb_status = WB_RXSTAT;

	return(0);
}

static void
df_wb_rxeof_fixed(struct wb_softc *sc)
{
	struct ifnet *ifp = &sc->arpcom.ac_if;
	struct mbuf *m, *m0;
	struct wb_chain_onefrag *cur_rx;
	int total_len = 0;
	uint32_t rxstat;

	for (;;) {
		rxstat = sc->wb_cdata.wb_rx_head->wb_ptr->wb_status;
		if (rxstat & WB_RXSTAT_OWN)		/* <-- FIX (fix.diff) */
			break;				/* was: == 0 */

		cur_rx = sc->wb_cdata.wb_rx_head;
		sc->wb_cdata.wb_rx_head = cur_rx->wb_nextdesc;

		m = cur_rx->wb_mbuf;

		if ((rxstat & WB_RXSTAT_MIIERR) ||
		    (WB_RXBYTES(cur_rx->wb_ptr->wb_status) < WB_MIN_FRAMELEN) ||
		    (WB_RXBYTES(cur_rx->wb_ptr->wb_status) > 1536) ||
		    (rxstat & WB_RXSTAT_LASTFRAG) == 0||
		    (rxstat & WB_RXSTAT_RXCMP) == 0) {
			IFNET_STAT_INC(ifp, ierrors, 1);
			df_wb_newbuf(sc, cur_rx, m);
			if_printf(ifp, "receiver babbling: possible chip "
				  "bug, forcing reset\n");
			return;
		}

		if (rxstat & WB_RXSTAT_RXERR) {
			IFNET_STAT_INC(ifp, ierrors, 1);
			df_wb_newbuf(sc, cur_rx, m);
			break;
		}

		/* No errors; receive the packet. */
		total_len = WB_RXBYTES(cur_rx->wb_ptr->wb_status);

		total_len -= ETHER_CRC_LEN;

		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
			      total_len + ETHER_ALIGN, 0, ifp);
		df_wb_newbuf(sc, cur_rx, m);
		if (m0 == NULL) {
			IFNET_STAT_INC(ifp, ierrors, 1);
			break;
		}
		m_adj(m0, ETHER_ALIGN);
		m = m0;

		IFNET_STAT_INC(ifp, ipackets, 1);
		ifp->if_input(ifp, m, NULL, -1);
	}
}
/* ================== end of fixed comparator ======================= */

static void
df_ring_probe(const char *tag)
{
	struct wb_chain_onefrag *c0 = &df_sc.wb_cdata.wb_rx_chain[0];
	uint32_t st = c0->wb_ptr->wb_status;

	kprintf("df4266: [%s] head==chain0:%d slot0.status=%#010x OWN:%d "
	    "RXLEN:%u mbuf=%p wb_data=%#010x\n",
	    tag, df_sc.wb_cdata.wb_rx_head == c0, st,
	    !!(st & WB_RXSTAT_OWN), WB_RXBYTES(st), c0->wb_mbuf,
	    c0->wb_ptr->wb_data);
}

/* 64-byte "received frame" (60 payload + 4 faux CRC), iota payload */
static uint8_t df_frame[64];

static void
df_craft_frame(void)
{
	struct mbuf *m = df_sc.wb_cdata.wb_rx_chain[0].wb_mbuf;
	int i;

	for (i = 0; i < ETHER_ADDR_LEN; i++)
		df_frame[i] = 0xFF;			/* broadcast dst */
	df_frame[6] = 0x00; df_frame[7] = 0xDF; df_frame[8] = 0x42;
	df_frame[9] = 0x66; df_frame[10] = 0x00; df_frame[11] = 0x01;
	df_frame[12] = 0xDF; df_frame[13] = 0x42;	/* ethertype */
	for (i = 14; i < 60; i++)
		df_frame[i] = (uint8_t)i;
	df_frame[60] = 0xDE; df_frame[61] = 0xAD;	/* faux CRC */
	df_frame[62] = 0xBE; df_frame[63] = 0xEF;

	/* the chip DMAs the frame into the buffer wb_newbuf armed */
	bcopy(df_frame, mtod(m, uint8_t *), sizeof(df_frame));
}

static int
df_setup(void)
{
	struct ifnet *ifp = &df_sc.arpcom.ac_if;

	bzero(df_mmio, sizeof(df_mmio));
	bzero(df_ifdata, sizeof(df_ifdata));

	callout_init(&df_sc.wb_stat_timer);
	lwkt_serialize_init(&df_ser);

	df_miibus_dev.softc = &df_mii;		/* device_get_softc() -> mii */

	/* post-wb_attach softc fields the dispatched code touches */
	df_sc.wb_miibus = &df_miibus_dev;
	df_sc.wb_ldata = &df_ldata;
	df_sc.wb_cachesize = 0;
	df_sc.wb_btag = (bus_space_tag_t)X86_64_BUS_SPACE_MEM;
	df_sc.wb_bhandle = (bus_space_handle_t)(uintptr_t)df_mmio;

	/* post-ether_ifattach ifnet state (wb_attach:768-797 + if_attach
	 * if_snd/subqueue setup, net/if.c:592-640 — wb_stop/wb_init reach
	 * ifq_clr_oactive -> ifsq->ifsq_hw_oactive, so altq_subq must be
	 * a real subqueue, not NULL) */
	strlcpy(ifp->if_xname, "dfwb0", sizeof(ifp->if_xname));
	ifp->if_softc = &df_sc;
	ifp->if_serializer = &df_ser;
	ifp->if_input = df_input;
	ifp->if_data_pcpu = df_ifdata;
	ifp->if_flags = IFF_UP | IFF_BROADCAST | IFF_SIMPLEX |
	    IFF_MULTICAST | IFF_RUNNING;

	ifp->if_snd.altq_subq_cnt = 1;
	ifp->if_snd.altq_subq = &df_subq;
	ifp->if_snd.altq_ifp = ifp;
	ifp->if_snd.altq_maxlen = WB_TX_LIST_CNT - 1;
	lwkt_serialize_init(&df_subq.ifsq_lock);
	df_subq.ifsq_index = 0;
	df_subq.ifsq_altq = &ifp->if_snd;
	df_subq.ifsq_ifp = ifp;
	df_subq.ifsq_maxlen = ifp->if_snd.altq_maxlen;
	df_subq.ifsq_maxbcnt = df_subq.ifsq_maxlen * MCLBYTES;
	df_subq.ifsq_enqueue = ifsq_classic_enqueue;
	df_subq.ifsq_dequeue = ifsq_classic_dequeue;
	df_subq.ifsq_request = ifsq_classic_request;
	ifq_set_ready(&ifp->if_snd);

	/* layout cross-check vs the running kernel's compiled offsets
	 * (wb_stop disasm: if_timer=+0x6a wb_bhandle=+0x3c0 wb_btag=+0x3c8
	 *  wb_ldata=+0x400 wb_rx_chain[0]=+0x450 wb_stat_timer=+0x1e68
	 *  if_snd.altq_subq=+0x210) */
	kprintf("df4266: layout: sizeof(wb_softc)=%#zx if_timer=%#zx "
	    "bhandle=%#zx btag=%#zx ldata=%#zx rx_chain0=%#zx "
	    "stat_timer=%#zx snd.altq_subq=%#zx\n",
	    sizeof(struct wb_softc),
	    __offsetof(struct wb_softc, arpcom.ac_if.if_timer),
	    __offsetof(struct wb_softc, wb_bhandle),
	    __offsetof(struct wb_softc, wb_btag),
	    __offsetof(struct wb_softc, wb_ldata),
	    __offsetof(struct wb_softc, wb_cdata.wb_rx_chain[0]),
	    __offsetof(struct wb_softc, wb_stat_timer),
	    __offsetof(struct wb_softc, arpcom.ac_if.if_snd.altq_subq));

	return (0);
}

/* Phase 0: arm the ring with the kernel's OWN wb_init */
static int
df_phase0(void)
{
	kprintf("df4266: === Phase 0: fabricate post-attach softc; dispatch "
	    "REAL wb_init (its inlined wb_list_rx_init arms the ring) ===\n");

	p_wb_init(&df_sc);

	df_ring_probe("P0-after-REAL-wb_init");
	if (df_sc.wb_cdata.wb_rx_head != &df_sc.wb_cdata.wb_rx_chain[0] ||
	    df_sc.wb_cdata.wb_rx_chain[0].wb_mbuf == NULL) {
		kprintf("df4266: P0: ring unexpectedly not armed\n");
		return (-1);
	}
	kprintf("df4266: P0: ring armed by the kernel's own code: 64 mbufs, "
	    "descriptors WB_RXSTAT=%#x (FIRSTFRAG|LASTFRAG|OWN — chip-owned)\n",
	    WB_RXSTAT);
	kprintf("df4266: P0: NOTE (known finding DF-4267): wb_rx_chain[0]."
	    "wb_nextdesc == &wb_rx_chain[0]: %d — production collapsed-ring "
	    "state, kept as-is\n",
	    df_sc.wb_cdata.wb_rx_chain[0].wb_nextdesc ==
	      &df_sc.wb_cdata.wb_rx_chain[0]);
	return (0);
}

/* S1: chip completed a frame (write-back: OWN cleared) — THE bug */
static void
df_phase_s1(void)
{
	struct wb_chain_onefrag *c0 = &df_sc.wb_cdata.wb_rx_chain[0];
	uint32_t crafted;
	u_long ip, ie;
	int deliv0 = df_delivered;

	kprintf("df4266: === S1: chip COMPLETED a frame in slot 0 "
	    "(write-back: OWN=0, RXCMP|LASTFRAG|FIRSTFRAG set, len 64) "
	    "===\n");

	bzero(df_ifdata, sizeof(df_ifdata));
	df_craft_frame();
	crafted = WB_RXSTAT_RXCMP | WB_RXSTAT_LASTFRAG |
	    WB_RXSTAT_FIRSTFRAG | (64 << 16);		/* OWN == 0 */
	df_ldata.wb_rx_list[0].wb_status = crafted;
	df_ring_probe("S1-crafted");

	p_wb_rxeof(&df_sc);				/* REAL handler */

	ip = DF_STAT(ifd_ipackets);
	ie = DF_STAT(ifd_ierrors);
	df_ring_probe("S1-after-REAL-wb_rxeof");
	kprintf("df4266: S1: delivered=%d ipackets=%lu ierrors=%lu "
	    "slot0 re-armed:%s head advanced:%s\n",
	    df_delivered - deliv0, ip, ie,
	    df_ldata.wb_rx_list[0].wb_status != crafted ? "YES" : "no",
	    df_sc.wb_cdata.wb_rx_head != c0 ? "YES" : "no");

	if (df_delivered == deliv0 && ip == 0 && ie == 0 &&
	    df_ldata.wb_rx_list[0].wb_status == crafted &&
	    df_sc.wb_cdata.wb_rx_head == c0)
		kprintf("df4266: *** S1 BUG CONFIRMED: the REAL wb_rxeof "
		    "broke immediately on the chip-COMPLETED descriptor "
		    "(OWN=0, if_wb.c:974-975): frame DROPPED, descriptor "
		    "never recycled, ipackets permanently 0 — RX dead ***\n");
	else
		kprintf("df4266: S1: UNEXPECTED outcome — inspect markers\n");
}

/* S1fix: identical state, one-line-fixed comparator (counterfactual) */
static void
df_phase_s1fix(void)
{
	u_long ip;
	int deliv0 = df_delivered;

	kprintf("df4266: === S1fix: IDENTICAL state, one-line-FIXED "
	    "comparator (verbatim wb_rxeof; loop condition per fix.diff) "
	    "===\n");

	df_wb_rxeof_fixed(&df_sc);

	ip = DF_STAT(ifd_ipackets);
	df_ring_probe("S1fix-after-fixed-comparator");
	kprintf("df4266: S1fix: delivered=%d ipackets=%lu slot0.status="
	    "%#010x (re-armed to WB_RXSTAT: %s)\n",
	    df_delivered - deliv0, ip, df_ldata.wb_rx_list[0].wb_status,
	    df_ldata.wb_rx_list[0].wb_status == WB_RXSTAT ? "YES" : "no");

	if (df_delivered == deliv0 + 1)
		kprintf("df4266: *** S1fix: the SAME descriptor state IS "
		    "deliverable — only the inverted OWN test at if_wb.c:974 "
		    "blocks the production handler ***\n");
	else
		kprintf("df4266: S1fix: UNEXPECTED outcome\n");
}

/* S2: armed idle ring — chip-owned descriptors PROCESSED + reset storm */
static void
df_phase_s2(void)
{
	int i;
	struct mbuf *m_before;
	struct timeval a, b;
	long us;

	kprintf("df4266: === S2: armed idle ring (all OWN=1, exactly what "
	    "wb_init leaves) — per-dispatch cost of the inverted loop "
	    "===\n");

	bzero(df_mmio, sizeof(df_mmio));
	bzero(df_ifdata, sizeof(df_ifdata));
	p_wb_init(&df_sc);			/* re-arm: production state */
	df_delivered = 0;
	df_ring_probe("S2-armed");

	for (i = 0; i < 3; i++) {
		u_long ip, ie;

		m_before = df_sc.wb_cdata.wb_rx_chain[0].wb_mbuf;
		microuptime(&a);
		p_wb_rxeof(&df_sc);		/* REAL handler */
		microuptime(&b);
		us = (b.tv_sec - a.tv_sec) * 1000000 + b.tv_usec - a.tv_usec;
		ip = DF_STAT(ifd_ipackets);
		ie = DF_STAT(ifd_ierrors);
		kprintf("df4266: S2: dispatch %d: ipackets=%lu ierrors=%lu "
		    "delivered=%d mbuf0 %p->%p (ring re-inited: %s) "
		    "elapsed=%ld us\n",
		    i, ip, ie, df_delivered, m_before,
		    df_sc.wb_cdata.wb_rx_chain[0].wb_mbuf,
		    df_sc.wb_cdata.wb_rx_chain[0].wb_mbuf != m_before ?
		      "YES" : "no", us);
	}

	kprintf("df4266: *** S2 BUG CONFIRMED: every dispatch PROCESSED a "
	    "chip-OWNED descriptor: head popped, ierrors++, 'receiver "
	    "babbling', wb_fixmedia+wb_reset+wb_init = full 64-mbuf ring "
	    "teardown/re-init PER INTERRUPT-equivalent (production: "
	    "wb_intr:1137-1147 pays this for every arriving frame) while "
	    "zero frames are delivered ***\n");
}

/* S3: chip-owned descriptor that looks complete (mid-write-back) */
static void
df_phase_s3(void)
{
	u_long ip, ie;
	uint32_t crafted;

	kprintf("df4266: === S3: descriptor STILL chip-owned (OWN=1) but "
	    "looking complete — the mid-write-back transient the inverted "
	    "loop wrongly accepts ===\n");

	bzero(df_mmio, sizeof(df_mmio));
	bzero(df_ifdata, sizeof(df_ifdata));
	p_wb_init(&df_sc);
	df_delivered = 0;

	df_craft_frame();
	crafted = WB_RXSTAT_OWN | WB_RXSTAT_RXCMP | WB_RXSTAT_LASTFRAG |
	    WB_RXSTAT_FIRSTFRAG | (64 << 16);		/* OWN STILL SET */
	df_ldata.wb_rx_list[0].wb_status = crafted;
	df_ring_probe("S3-crafted");

	p_wb_rxeof(&df_sc);				/* REAL handler */

	ip = DF_STAT(ifd_ipackets);
	ie = DF_STAT(ifd_ierrors);
	df_ring_probe("S3-after-REAL-wb_rxeof");
	kprintf("df4266: S3: delivered=%d ipackets=%lu ierrors=%lu "
	    "slot0.status=%#010x (crafted %#010x; re-armed under the chip: "
	    "%s)\n", df_delivered, ip, ie,
	    df_ldata.wb_rx_list[0].wb_status, crafted,
	    df_ldata.wb_rx_list[0].wb_status == WB_RXSTAT ? "YES" : "no");

	if (df_delivered >= 1 && ip >= 1)
		kprintf("df4266: *** S3 BUG CONFIRMED: frame ACCEPTED from a "
		    "descriptor with OWN=1 (chip still owns it) and the "
		    "descriptor RE-ARMED (status rewritten to WB_RXSTAT) "
		    "under the chip — driver and hardware now disagree about "
		    "who owns descriptor 0 and its mbuf ***\n");
	else
		kprintf("df4266: S3: UNEXPECTED outcome\n");
}

static int
df_sysctl_go(SYSCTL_HANDLER_ARGS)
{
	int error, go = 0;

	error = sysctl_handle_int(oidp, &go, 0, req);
	if (error || req->newptr == NULL)
		return (error);
	if (go != 1 || df_ran)
		return (EPERM);
	df_ran = 1;

	if (p_wb_rxeof == NULL || p_wb_init == NULL || p_wb_stop == NULL) {
		kprintf("df4266: kernel addresses not set — use "
		    "kern.df4266.{rxeof,init,stop}\n");
		return (EINVAL);
	}
	kprintf("df4266: dispatching REAL kernel handlers (built-in "
	    "'device wb'): wb_rxeof=%p wb_init=%p wb_stop=%p\n",
	    p_wb_rxeof, p_wb_init, p_wb_stop);

	df_setup();
	lwkt_serialize_enter(&df_ser);		/* as wb_intr would */
	if (df_phase0() == 0) {
		df_phase_s1();
		df_phase_s1fix();
		df_phase_s2();
		df_phase_s3();
	}
	p_wb_stop(&df_sc);			/* frees ring mbufs */
	callout_stop(&df_sc.wb_stat_timer);	/* defuse wb_tick */
	lwkt_serialize_exit(&df_ser);
	kprintf("df4266: SURVIVED — see markers above; guest stays up\n");
	return (0);
}
SYSCTL_PROC(_kern_df4266, OID_AUTO, go,
    CTLTYPE_INT | CTLFLAG_RW, NULL, 0, df_sysctl_go, "I",
    "run the DF-4266 scenarios (needs rxeof/init/stop set)");

static int
df_modevent(module_t mod, int type, void *arg)
{
	switch (type) {
	case MOD_LOAD:
		return (0);
	case MOD_UNLOAD:
		/* state is static module memory; just defuse the callout */
		if (df_ran)
			callout_stop(&df_sc.wb_stat_timer);
		return (0);
	default:
		return (0);
	}
}

static moduledata_t df_mod = { "df4266_wb_poc", df_modevent, NULL };
DECLARE_MODULE(df4266_wb_poc, df_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
