From: Moritz Buhl Subject: bwfm fixes To: tech@openbsd.org Date: Mon, 4 Aug 2025 20:19:08 +0200 Dear tech, I currently use a MacBook m2 and I always have trouble with the bwfm in it. Here are three fixes: 1. receive EAPOL event messages. After debugging this for a few days, I noticed that EAPOL frames do not cause an interrupt and with my macbook the messag either comes with the previous WL_EVENTS that change the link state and finish the ASSOC state, or the firmware crashes about 100ms later. I can imagine this may also help with crashes in AP mode on other devices. 2. do ieee80211 state changes inside of the interrupt handler. To my understanding this is in line with outher drivers and it is necessary for the wpa handshake to process it within 100 ms which we could miss because of the additional queueing. 3. process control messages before rx messages. Otherwise a EAPOL frame could be processed before changing from ASSOC to RUN. I would appreciate additional testing on other devices. mbuhl Index: ic/bwfm.c =================================================================== RCS file: /cvs/src/sys/dev/ic/bwfm.c,v diff -u -p -r1.111 bwfm.c --- ic/bwfm.c 19 Feb 2024 21:23:02 -0000 1.111 +++ ic/bwfm.c 4 Aug 2025 15:43:12 -0000 @@ -494,6 +494,7 @@ bwfm_init(struct ifnet *ifp) BWFM_EVENT(BWFM_E_LINK); BWFM_EVENT(BWFM_E_AUTH); BWFM_EVENT(BWFM_E_ASSOC); + BWFM_EVENT(BWFM_E_EAPOL_MSG); BWFM_EVENT(BWFM_E_DEAUTH); BWFM_EVENT(BWFM_E_DISASSOC); BWFM_EVENT(BWFM_E_ESCAN_RESULT); @@ -503,6 +504,7 @@ bwfm_init(struct ifnet *ifp) BWFM_EVENT(BWFM_E_AUTH_IND); BWFM_EVENT(BWFM_E_ASSOC_IND); BWFM_EVENT(BWFM_E_REASSOC_IND); + BWFM_EVENT(BWFM_E_EAPOL_MSG); BWFM_EVENT(BWFM_E_DEAUTH_IND); BWFM_EVENT(BWFM_E_DISASSOC_IND); BWFM_EVENT(BWFM_E_ESCAN_RESULT); @@ -2551,12 +2551,44 @@ void bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m) { int s; + struct ieee80211com *ic = &sc->sc_ic; + struct bwfm_event *e = mtod(m, void *); s = splnet(); + switch (ntohl(e->msg.event_type)) { + case BWFM_E_AUTH: + if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && + ic->ic_state == IEEE80211_S_AUTH) { + ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); + goto done; + } + goto enqueue; + case BWFM_E_ASSOC: + if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && + ic->ic_state == IEEE80211_S_ASSOC) { + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + } else if (ntohl(e->msg.status) != BWFM_E_STATUS_UNSOLICITED) { + goto enqueue; + } + goto done; + case BWFM_E_LINK: + if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && + ntohl(e->msg.reason) == 0) + goto done; + goto enqueue; + default: + goto enqueue; + } +done: + splx(s); + m_freem(m); + return; +enqueue: ml_enqueue(&sc->sc_evml, m); splx(s); task_add(sc->sc_taskq, &sc->sc_task); + return; } void @@ -2631,18 +2663,10 @@ bwfm_rx_event_cb(struct bwfm_softc *sc, break; } case BWFM_E_AUTH: - if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && - ic->ic_state == IEEE80211_S_AUTH) - ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); - else - ieee80211_begin_scan(ifp); + ieee80211_begin_scan(ifp); break; case BWFM_E_ASSOC: - if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && - ic->ic_state == IEEE80211_S_ASSOC) - ieee80211_new_state(ic, IEEE80211_S_RUN, -1); - else if (ntohl(e->msg.status) != BWFM_E_STATUS_UNSOLICITED) - ieee80211_begin_scan(ifp); + ieee80211_begin_scan(ifp); break; case BWFM_E_DEAUTH: case BWFM_E_DISASSOC: @@ -2650,9 +2674,6 @@ bwfm_rx_event_cb(struct bwfm_softc *sc, ieee80211_begin_scan(ifp); break; case BWFM_E_LINK: - if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && - ntohl(e->msg.reason) == 0) - break; /* Link status has changed */ if (ic->ic_state > IEEE80211_S_SCAN) ieee80211_begin_scan(ifp); Index: pci/if_bwfm_pci.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_bwfm_pci.c,v diff -u -p -r1.77 if_bwfm_pci.c --- pci/if_bwfm_pci.c 12 Jul 2024 08:33:25 -0000 1.77 +++ pci/if_bwfm_pci.c 4 Aug 2025 15:45:07 -0000 @@ -2369,9 +2369,9 @@ bwfm_pci_intr(void *v) mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB; if (status & mask) { + bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml); bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml); bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml); - bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml); if (ifiq_input(&ifp->if_rcv, &ml)) if_rxr_livelocked(&sc->sc_rxbuf_ring);