Thanks for the review.
You are right, fixing this at the source is better. Here is v2 with
three changes instead of the conditional check in urtw_newstate():
1. In urtw_attach(), right after ieee80211_media_init() -- ic_bss has
just been allocated by ieee80211_node_lateattach() with ni_chan set
to IEEE80211_CHAN_ANYC (NULL). Give it a real channel immediately.
2. In urtw_init(), before the state machine transition.
3. In urtw_8187b_init(), same as (2) for the 8187B path.
The v1 hunk in urtw_newstate() is gone: once attach sets ni_chan,
the ANYC condition can never be true -- it would be dead code.
Tested on StarFive VisionFive 2 (riscv64), OpenBSD 7.9.
No panic on ifconfig up, scan, up/down cycles, USB replug,
and monitor mode.
Index: sys/dev/usb/if_urtw.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_urtw.c,v
retrieving revision 1.74
diff -u -p -r1.74 if_urtw.c
--- sys/dev/usb/if_urtw.c
+++ sys/dev/usb/if_urtw.c
@@ -723,6 +723,14 @@ urtw_attach(struct device *parent, struc
ic->ic_newstate = urtw_newstate;
ieee80211_media_init(ifp, urtw_media_change, ieee80211_media_status);
+ /*
+ * ic_bss is allocated by ieee80211_node_lateattach(), called from
+ * ieee80211_media_init() above, and starts out with ni_chan set to
+ * IEEE80211_CHAN_ANYC (NULL). Give it a real channel right away so
+ * that nothing can dereference it before the interface comes up.
+ */
+ ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+
#if NBPFILTER > 0
bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
@@ -2293,6 +2301,14 @@ urtw_init(struct ifnet *ifp)
ifp->if_timer = 1;
+ /*
+ * Make sure ic_bss->ni_chan is a real channel before the 802.11
+ * state machine runs: ieee80211_newstate() dereferences it, e.g.
+ * in ieee80211_node_abg_mode(), without checking for
+ * IEEE80211_CHAN_ANYC (NULL).
+ */
+ ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+
if (ic->ic_opmode == IEEE80211_M_MONITOR)
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
else
@@ -3694,6 +3710,14 @@ urtw_8187b_init(struct ifnet *ifp)
ifp->if_timer = 1;
+ /*
+ * Make sure ic_bss->ni_chan is a real channel before the 802.11
+ * state machine runs: ieee80211_newstate() dereferences it, e.g.
+ * in ieee80211_node_abg_mode(), without checking for
+ * IEEE80211_CHAN_ANYC (NULL).
+ */
+ ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+
if (ic->ic_opmode == IEEE80211_M_MONITOR)
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
else