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

Reply via email to