# DF-3327 — Remote kernel panic in `hwmp_send_action`: PREP sent along a never-validated (zero) nexthop

**File:** `sys/netproto/802_11/wlan/ieee80211_hwmp.c`
**Severity:** High (unauthenticated adjacent-network DoS, default-config mesh vap)
**Verdict:** REPRODUCED — `panic: null node` on the stock INVARIANTS kernel; fix validated.

## What

A single broadcast-target HWMP PREQ action frame makes `hwmp_recv_preq()`
emit a *proactive PREP* addressed to the nexthop of an originator route that
exists but was never marked VALID. Such a route is M_ZERO-allocated
(`ieee80211_mesh.c:203-215`), so its nexthop is `00:00:00:00:00:00`.
`hwmp_send_action()` resolves that address with
`ieee80211_mesh_find_txnode()`, which returns NULL for an unrouted address
(`ieee80211_mesh.c:1028-1037`), then hits
`KASSERT(ni != NULL, ("null node"))` (`ieee80211_hwmp.c:636`) — panic on
INVARIANTS kernels; on production kernels the next line (`ic = ni->ni_ic`,
`ieee80211_hwmp.c:637`) is a NULL deref → fatal page fault. Same sink is
reachable from PREP propagation (`ieee80211_hwmp.c:1558`) and the
intermediate PREP reply (`ieee80211_hwmp.c:1303`).

Why the route stays INVALID: for a fresh originator route `hr_seq == 0`; a
PREQ with `origseq == 0` and metric not better than 0 satisfies neither
update branch (`ieee80211_hwmp.c:1090-1102`) nor the discard branch
(`:1103-1106`), so processing falls through with the route INVALID, yet the
proactive branch (`:1216-1255`) still sends a PREP to
`rtorig->rt_nexthop == 00:00:00:00:00:00`.

## Reproduce

Requires the repo-root working dir and the QEMU guest (see `dfbsd-qemu/`).

    sh findings/poc/DF-3327/build.sh     # compile extended fwm.ko in guest
    sh findings/poc/DF-3327/run.sh       # boot mesh vap, peer, fire step 30

Expected (stock kernel): serial console shows

    fwm: inject HWMP PREQ origseq=0 targ=bc TO (proactive PREP to zero nexthop)
    panic: null node
    hwmp_send_action() at hwmp_send_action+0x4ee
    hwmp_recv_action_meshpath() at ...
    Debugger("panic")

and the guest wedges in ddb (reset afterwards: `dfbsd-qemu/vm.sh reset with-src`).

## Fix validation

`fix.diff` adds a NULL check in `hwmp_send_action()` (drop + ENOENT).
Applied in-guest, `make -j6 nativekernel KERNCONF=X86_64_GENERIC` +
`make installkernel`, reboot into kernel #1, same PoC (twice): **no panic,
guest stays up, PREQ still fully processed** (forwarded broadcast PREQ
visible in `kern.fwm_txlog`). See `fix_run.log`, `fix_build.log`.

## Harness

`fwm.c` extends the DF-3286/3287 shared software-radio KLD. New step 30
builds the 65-byte action frame:

    802.11 hdr | cat=13 (MESH) code=1 (HWMP) | PREQ IE (130) len=37:
    flags=0 hop=0 ttl=32 id=0x41414141 orig=02:00:00:00:e0:01 (fresh)
    origseq=0 lifetime=5000 metric=0 tcount=1
    target: flags=0x01 (TO) addr=ff:ff:ff:ff:ff:ff seq=0

Peer establishment (step 4: beacon + OPEN + CONFIRM) is required because
`ieee80211_recv_action()` gates CAT_MESH frames on an ESTABLISHED link
(`ieee80211_action.c:243-256`); peering is auto-granted on default-config
mesh vaps (`ieee80211_mesh.c:683` — `MESHFLAGS_AP|MESHFLAGS_FWD`).
