# DF-4996 — ral_pci_attach() error path runs the child detach twice: ieee80211_ifdetach() on a never-attached ieee80211com NULL-writes in LIST_REMOVE → kernel panic (double-free tail)

## Where

`sys/dev/netif/ral/if_ral_pci.c` (PCI front-end for rt2560/rt2661/rt2860).

## What / expected

When the child attach (`rt2560_attach`/`rt2661_attach`/`rt2860_attach`) fails
(ring DMA allocation failure, or RT2860 "timeout waiting for NIC to
initialize"), the child **already unwound itself** (frees all rings, calls
`lockuninit`) and **never called `ieee80211_ifattach()`**.  The glue then calls
the *full* `ral_pci_detach()`, which dispatches the child `detach()` a second
time.  `ieee80211_ifdetach()` unconditionally executes
`LIST_REMOVE(ic, ic_next)` (`sys/sys/queue.h:460-468`); on the zeroed,
never-attached `ic`, `ic_next.le_prev == NULL`, so `*(elm)->field.le_prev = …`
writes through NULL → fatal trap 12 at virtual address 0.  Had that somehow
survived, the subsequent `rt2560_free_tx_ring()` calls double-free every DMA
ring (`ring->desc`/`ring->data` are not NULLed after freeing).

## Build (on the audit DragonFly guest)

```
cd /root/df4996
make SYSDIR=/usr/src/sys
```

## Run (guest)

```
kldload ./df4996.ko          # phase 1: safe, prints DF-4997 offset evidence
dmesg | grep DF499
sysctl kern.df4996=trigger   # phase 2: PANICS the guest (fatal trap 12, VA 0)
```

The guest has no Ralink PCI hardware, so the ral attach-failure *trigger*
cannot run end-to-end.  The module reproduces the exact **sink** with the
exact **precondition**: a freshly-zeroed `ieee80211com` — which is precisely
the state of the child softc on that path (newbus zeroes device softcs) — is
passed to `ieee80211_ifdetach()`.

## Expected output (observed 2026-09-25, see run.log / run.2.log / panic.txt)

```
DF4996: zeroed ic=0xfffff8011935e200 (== ral child softc after failed attach: ieee80211_ifattach() never ran)
DF4996: invoking ieee80211_ifdetach(ic) ...
Fatal trap 12: page fault while in kernel mode
fault virtual address  = 0x0
Stopped at      ieee80211_ifdetach+0x124:  cmpq    (%rdx),%rbx
```

The panic lands inside `ieee80211_ifdetach` (the LIST_REMOVE through
`le_prev == NULL`), matching `wlan/ieee80211.c:423` + `queue.h:468`.
