# DF-5294 — rum_ratectl_task re-arms rvp->ratectl_ch unconditionally; the
# re-arm survives rum_vap_delete's drains and fires on the freed rum_vap

## What
```c
sys/bus/u4b/wlan/if_rum.c:3140
	usb_callout_reset(&rvp->ratectl_ch, hz, rum_ratectl_timeout, rvp);
```
The re-arm at the end of `rum_ratectl_task` is **unconditional** — there is
no `ratectl_run`-style guard.  Both wlan twins in this tree have the guard
that rum lacks:

```c
sys/bus/u4b/wlan/if_run.c:2497   if(sc->ratectl_run != RUN_RATECTL_OFF)
                                     usb_callout_reset(&sc->ratectl_ch, ...);
sys/bus/u4b/wlan/if_mtw.c:2401   if (sc->ratectl_run != MTW_RATECTL_OFF) { ... }
```
(and both clear the mask in their `*_vap_delete` BEFORE draining:
if_run.c:1017, if_mtw.c:895).

`rum_vap_delete()` (:709-721) drains in the vulnerable order:

```c
716: usb_callout_drain(&rvp->ratectl_ch);      /* callout_drain */
717: ieee80211_draintask(ic, &rvp->ratectl_task);
719: ieee80211_vap_detach(vap);   /* -> ieee80211_stop -> rum_newstate -> usb_callout_stop (:934) */
720: kfree(rvp, M_80211_VAP);
```

Failure interleaving: a task instance that completes during/after :716
re-arms the callout at :3140 (no guard); the re-armed callout can fire inside
the :718-:719 window (ratectl_deinit + `ether_ifdetach` — a heavyweight
teardown that can easily exceed one tick) and enqueue the task again; nothing
drains `ratectl_task` after :719, so it runs `rum_ratectl_task(rvp == freed)`
after :720 — dereferencing `vap->iv_ic`, `vap->iv_bss` on freed heap — and it
re-arms the callout on the freed object again, perpetuating the cycle
(`ieee80211_runtask` writes into freed memory on every enqueue).

Secondary correctness defect from the same line: a task instance queued
before a state transition re-arms the callout even after
`rum_newstate`'s `usb_callout_stop` (:934), so the ratectl loop keeps running
while the vap is down.

## Hardware gating
rum(4) needs RT2573 hardware — absent on the QEMU guest.  Evidence is the
line-level protocol trace plus `rum_ratectl_drain.c`, a userland model of the
callout/task/destroy protocol with the exact shipped order vs the guarded
fix, 3×10 s per mode on the guest.

## Build / Run / Expected
```
cc -O2 -pthread -Wall -o rum_ratectl_drain rum_ratectl_drain.c
./rum_ratectl_drain 10 0    # shipped: unguarded re-arm -> POST-FREE fires/tasks > 0
./rum_ratectl_drain 10 1    # fixed: guard cleared before drains -> exactly 0
```
See `run.log`: shipped 115/108/125 post-free callout fires and 111/108/127
post-free task runs over 360 destroy cycles per run; guarded 0/0.

## Fix
`fix.diff` (if_rum.c + if_rumvar.h) — add `sc->ratectl_run`, set in
`rum_ratectl_start`, cleared in `rum_newstate` (with the existing callout
stop) and in `rum_vap_delete` BEFORE the drains; guard the :3140 re-arm.
`git apply --check` clean.  Kernel fix validation hardware-gated
(`fix_status: not_testable`).
