Re: qwx use-after-free fix
Mark Kettenis <[email protected]> Thu, 16 Jul 2026 13:58:41 +0200
| Newsgroups | gmane.os.openbsd.tech |
|---|---|
| Message-ID | <[email protected]> |
> Date: Tue, 14 Jul 2026 18:24:24 +0200 > From: Stefan Sperling <[email protected]> > > Memory allocation failures in qwx_vif_alloc() can lead to crashes. > > The reason is that the driver will then use a stale vif pointer from > sc->vif_list from previous down/up cycles. The vif structure contains > DMA maps used for sending management frames. > > Rather than trying to fix our broken management of the vif list, > the patch at the bottom removes the list in favour of a single vif > structure, allocates DMA maps at attach time, and keeps them allocated > across down/up cycles. We keep a list of 8 maps, each of which can map > a single frame, so this shouldn't be wasteful. > > Here is a reproducer diff. > if you want to reproduce my findings, boot a kernel with it, then > suspend/resume once, then try to bring the interface up after resume. > Since this code uses BUS_DMA_NOWAIT the crash triggers by chance on > a stock kernel if this memory allocation path fails. Nice. And yes, while working on my "waitok" diff I ran into this bit of code and couldn't work out the lifetime of the vif structures. Lightly tested, but suspend/resume and hibernate still work on my amd64 laptop. ok kettenis@OB > CRASH: --- sys/dev/ic/qwx.c > CRASH: +++ sys/dev/ic/qwx.c > CRASH: @@ -116,6 +116,8 @@ hweight8(uint8_t x) > CRASH: > CRASH: /* #define QWX_DEBUG */ > CRASH: > CRASH: +static int qwx_resuming; > CRASH: + > CRASH: #include <dev/ic/qwxreg.h> > CRASH: #include <dev/ic/qwxvar.h> > CRASH: > CRASH: @@ -24022,8 +24024,13 @@ qwx_vif_alloc(struct qwx_softc *sc) > CRASH: for (i = 0; i < nitems(txmgmt->data); i++) { > CRASH: struct qwx_tx_data *tx_data = &txmgmt->data[i]; > CRASH: > CRASH: - ret = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, > CRASH: - BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &tx_data->map); > CRASH: + if (qwx_resuming && i > 6) { > CRASH: + ret = ENOMEM; > CRASH: + qwx_resuming = 0; > CRASH: + } else { > CRASH: + ret = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, > CRASH: + BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &tx_data->map); > CRASH: + } > CRASH: if (ret) { > CRASH: qwx_vif_free(sc, arvif); > CRASH: return NULL; > CRASH: @@ -27489,6 +27496,7 @@ qwx_activate(struct device *self, int act) > CRASH: sc->sc_dev.dv_xname); > CRASH: } > CRASH: rw_exit(&sc->ioctl_rwl); > CRASH: + qwx_resuming = 1; > CRASH: break; > CRASH: } > CRASH: > > > Fix: > > Replace virtual interface list with a single interface structure > > Should fix use of stale pointers on the vif list which caused crashes. > We do not support multiple interfaces per driver in our net80211 stack, > so this list inherited from Linux was pointless for us anyway. > > ok? > > M sys/dev/ic/qwx.c | 59+ 138- > M sys/dev/ic/qwxvar.h | 1+ 6- > > 2 files changed, 60 insertions(+), 144 deletions(-) > > commit - 03332418d3c68eaa3a6cced9f13621a1dc17c1f9 > commit + 8b38c9a0ec77696975740fa34e14b8f85f513bbf > blob - 62d805dffc20300433d2d806d92aa06b3801b63d > blob + 55106d1812e2c7b3a521b044d36f76c7fc232b84 > --- sys/dev/ic/qwx.c > +++ sys/dev/ic/qwx.c > @@ -168,7 +168,6 @@ int qwx_wmi_vdev_install_key(struct qwx_softc *, > int qwx_dp_peer_rx_pn_replay_config(struct qwx_softc *, struct qwx_vif *, > struct ieee80211_node *, struct ieee80211_key *, int); > void qwx_setkey_clear(struct qwx_softc *); > -void qwx_vif_free_all(struct qwx_softc *); > void qwx_dp_stop_shadow_timers(struct qwx_softc *); > void qwx_ce_stop_shadow_timers(struct qwx_softc *); > int qwx_wmi_vdev_set_param_cmd(struct qwx_softc *, uint32_t, uint8_t, > @@ -420,6 +419,24 @@ qwx_del_task_all(struct qwx_softc *sc) > } > > void > +qwx_vif_purge(struct qwx_softc *sc) > +{ > + struct qwx_vif *arvif = &sc->sc_vif; > + struct qwx_txmgmt_queue *txmgmt; > + int i; > + > + txmgmt = &arvif->txmgmt; > + for (i = 0; i < nitems(txmgmt->data); i++) { > + struct qwx_tx_data *tx_data = &txmgmt->data[i]; > + > + if (tx_data->m) { > + m_freem(tx_data->m); > + tx_data->m = NULL; > + } > + } > +} > + > +void > qwx_stop(struct ifnet *ifp) > { > struct qwx_softc *sc = ifp->if_softc; > @@ -497,7 +514,7 @@ qwx_stop(struct ifnet *ifp) > /* free some DMA allocations and power off hardware */ > qwx_core_deinit(sc); > > - qwx_vif_free_all(sc); > + qwx_vif_purge(sc); > > splx(s); > } > @@ -574,7 +591,7 @@ qwx_tx(struct qwx_softc *sc, struct mbuf *m, struct ie > { > struct ieee80211com *ic = &sc->sc_ic; > struct ieee80211_frame *wh; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > uint8_t frame_type; > > @@ -884,7 +901,7 @@ qwx_add_sta_key(struct qwx_softc *sc, struct ieee80211 > struct ieee80211com *ic = &sc->sc_ic; > struct qwx_node *nq = (struct qwx_node *)ni; > struct ath11k_peer *peer; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > int ret = 0; > uint32_t flags = 0; > @@ -949,7 +966,7 @@ qwx_del_sta_key(struct qwx_softc *sc, struct ieee80211 > struct ieee80211_key *k) > { > struct qwx_node *nq = (struct qwx_node *)ni; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > int ret = 0; > > ret = qwx_wmi_install_key_cmd(sc, arvif, ni->ni_macaddr, k, 0, 1); > @@ -1008,7 +1025,7 @@ qwx_setkey_task(void *arg) > void > qwx_clear_hwkeys(struct qwx_softc *sc, struct ath11k_peer *peer) > { > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > struct wmi_vdev_install_key_arg arg = { > .vdev_id = arvif->vdev_id, > @@ -13266,7 +13283,6 @@ void > qwx_scan_event(struct qwx_softc *sc, struct mbuf *m) > { > struct wmi_scan_event scan_ev = { 0 }; > - struct qwx_vif *arvif; > > if (qwx_pull_scan_ev(sc, m, &scan_ev) != 0) { > printf("%s: failed to extract scan event", > @@ -13276,20 +13292,7 @@ qwx_scan_event(struct qwx_softc *sc, struct mbuf *m) > #ifdef notyet > rcu_read_lock(); > #endif > - TAILQ_FOREACH(arvif, &sc->vif_list, entry) { > - if (arvif->vdev_id == scan_ev.vdev_id) > - break; > - } > - > - if (!arvif) { > - printf("%s: received scan event for unknown vdev\n", > - sc->sc_dev.dv_xname); > #if 0 > - rcu_read_unlock(); > -#endif > - return; > - } > -#if 0 > spin_lock_bh(&ar->data_lock); > #endif > DNPRINTF(QWX_D_WMI, > @@ -13375,7 +13378,6 @@ qwx_pull_chan_info_ev(struct qwx_softc *sc, uint8_t *e > void > qwx_chan_info_event(struct qwx_softc *sc, struct mbuf *m) > { > - struct qwx_vif *arvif; > struct wmi_chan_info_event ch_info_ev = {0}; > struct qwx_survey_info *survey; > int idx; > @@ -13403,20 +13405,6 @@ qwx_chan_info_event(struct qwx_softc *sc, struct mbuf > } > #ifdef notyet > rcu_read_lock(); > -#endif > - TAILQ_FOREACH(arvif, &sc->vif_list, entry) { > - if (arvif->vdev_id == ch_info_ev.vdev_id) > - break; > - } > - if (!arvif) { > - printf("%s: invalid vdev id in chan info ev %d\n", > - sc->sc_dev.dv_xname, ch_info_ev.vdev_id); > -#ifdef notyet > - rcu_read_unlock(); > -#endif > - return; > - } > -#ifdef notyet > spin_lock_bh(&ar->data_lock); > #endif > switch (sc->scan.state) { > @@ -13705,7 +13693,7 @@ qwx_wmi_process_mgmt_tx_comp(struct qwx_softc *sc, > struct wmi_mgmt_tx_compl_event *tx_compl_param) > { > struct ieee80211com *ic = &sc->sc_ic; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > struct ifnet *ifp = &ic->ic_if; > struct qwx_tx_data *tx_data; > > @@ -13891,7 +13879,6 @@ void > qwx_vdev_install_key_compl_event(struct qwx_softc *sc, struct mbuf *m) > { > struct wmi_vdev_install_key_complete_arg install_key_compl = { 0 }; > - struct qwx_vif *arvif; > > if (qwx_pull_vdev_install_key_compl_ev(sc, m, > &install_key_compl) != 0) { > @@ -13906,16 +13893,6 @@ qwx_vdev_install_key_compl_event(struct qwx_softc *sc, > ether_sprintf((u_char *)install_key_compl.macaddr), > install_key_compl.status); > > - TAILQ_FOREACH(arvif, &sc->vif_list, entry) { > - if (arvif->vdev_id == install_key_compl.vdev_id) > - break; > - } > - if (!arvif) { > - printf("%s: invalid vdev id in install key compl ev %d\n", > - sc->sc_dev.dv_xname, install_key_compl.vdev_id); > - return; > - } > - > sc->install_key_status = 0; > > if (install_key_compl.status != > @@ -23475,7 +23452,7 @@ qwx_mac_config_mon_status_default(struct qwx_softc *sc > int > qwx_mac_txpower_recalc(struct qwx_softc *sc, struct qwx_pdev *pdev) > { > - struct qwx_vif *arvif; > + struct qwx_vif *arvif = &sc->sc_vif; > int ret, txpower = -1; > uint32_t param; > uint32_t min_tx_power = sc->target_caps.hw_min_tx_power; > @@ -23483,15 +23460,10 @@ qwx_mac_txpower_recalc(struct qwx_softc *sc, struct qw > #ifdef notyet > lockdep_assert_held(&ar->conf_mutex); > #endif > - TAILQ_FOREACH(arvif, &sc->vif_list, entry) { > - if (arvif->txpower <= 0) > - continue; > + if (arvif->txpower <= 0) > + return 0; > > - if (txpower == -1) > - txpower = arvif->txpower; > - else > - txpower = MIN(txpower, arvif->txpower); > - } > + txpower = MIN(txpower, arvif->txpower); > > if (txpower == -1) > return 0; > @@ -23664,10 +23636,9 @@ qwx_mac_setup_vdev_params_mbssid(struct qwx_vif *arvif > } > > int > -qwx_mac_setup_vdev_create_params(struct qwx_vif *arvif, struct qwx_pdev *pdev, > - struct vdev_create_params *params) > +qwx_mac_setup_vdev_create_params(struct qwx_softc *sc, struct qwx_vif *arvif, > + struct qwx_pdev *pdev, struct vdev_create_params *params) > { > - struct qwx_softc *sc = arvif->sc; > int ret; > > params->if_id = arvif->vdev_id; > @@ -23969,70 +23940,45 @@ qwx_mac_vdev_start(struct qwx_softc *sc, struct qwx_vi > } > > void > -qwx_vif_free(struct qwx_softc *sc, struct qwx_vif *arvif) > +qwx_vif_free(struct qwx_softc *sc) > { > + struct qwx_vif *arvif = &sc->sc_vif; > struct qwx_txmgmt_queue *txmgmt; > int i; > > - if (arvif == NULL) > - return; > - > txmgmt = &arvif->txmgmt; > for (i = 0; i < nitems(txmgmt->data); i++) { > struct qwx_tx_data *tx_data = &txmgmt->data[i]; > > - if (tx_data->m) { > - m_freem(tx_data->m); > - tx_data->m = NULL; > - } > if (tx_data->map) { > bus_dmamap_destroy(sc->sc_dmat, tx_data->map); > tx_data->map = NULL; > } > } > - > - free(arvif, M_DEVBUF, sizeof(*arvif)); > } > > -void > -qwx_vif_free_all(struct qwx_softc *sc) > -{ > - struct qwx_vif *arvif; > - > - while (!TAILQ_EMPTY(&sc->vif_list)) { > - arvif = TAILQ_FIRST(&sc->vif_list); > - TAILQ_REMOVE(&sc->vif_list, arvif, entry); > - qwx_vif_free(sc, arvif); > - } > -} > - > -struct qwx_vif * > +int > qwx_vif_alloc(struct qwx_softc *sc) > { > - struct qwx_vif *arvif; > + struct qwx_vif *arvif = &sc->sc_vif; > struct qwx_txmgmt_queue *txmgmt; > int i, ret = 0; > const bus_size_t size = IEEE80211_MAX_LEN; > > - arvif = malloc(sizeof(*arvif), M_DEVBUF, M_NOWAIT | M_ZERO); > - if (arvif == NULL) > - return NULL; > - > + /* Allocate DMA maps used when sending management frames. */ > txmgmt = &arvif->txmgmt; > for (i = 0; i < nitems(txmgmt->data); i++) { > struct qwx_tx_data *tx_data = &txmgmt->data[i]; > > ret = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, > - BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &tx_data->map); > + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tx_data->map); > if (ret) { > - qwx_vif_free(sc, arvif); > - return NULL; > + qwx_vif_free(sc); > + return ENOMEM; > } > } > > - arvif->sc = sc; > - > - return arvif; > + return 0; > } > > int > @@ -24040,7 +23986,7 @@ qwx_mac_op_add_interface(struct qwx_pdev *pdev) > { > struct qwx_softc *sc = pdev->sc; > struct ieee80211com *ic = &sc->sc_ic; > - struct qwx_vif *arvif = NULL; > + struct qwx_vif *arvif = &sc->sc_vif; > struct vdev_create_params vdev_param = { 0 }; > #if 0 > struct peer_create_params peer_param; > @@ -24071,11 +24017,6 @@ qwx_mac_op_add_interface(struct qwx_pdev *pdev) > goto err; > } > > - arvif = qwx_vif_alloc(sc); > - if (arvif == NULL) { > - ret = ENOMEM; > - goto err; > - } > #if 0 > INIT_DELAYED_WORK(&arvif->connection_loss_work, > ath11k_mac_vif_sta_connection_loss_work); > @@ -24130,7 +24071,7 @@ qwx_mac_op_add_interface(struct qwx_pdev *pdev) > __func__, arvif->vdev_id, arvif->vdev_type, > arvif->vdev_subtype, sc->free_vdev_map); > > - ret = qwx_mac_setup_vdev_create_params(arvif, pdev, &vdev_param); > + ret = qwx_mac_setup_vdev_create_params(sc, arvif, pdev, &vdev_param); > if (ret) { > printf("%s: failed to create vdev parameters %d: %d\n", > sc->sc_dev.dv_xname, arvif->vdev_id, ret); > @@ -24150,13 +24091,7 @@ qwx_mac_op_add_interface(struct qwx_pdev *pdev) > ether_sprintf(ic->ic_myaddr), arvif->vdev_id); > sc->allocated_vdev_map |= 1U << arvif->vdev_id; > sc->free_vdev_map &= ~(1U << arvif->vdev_id); > -#ifdef notyet > - spin_lock_bh(&ar->data_lock); > -#endif > - TAILQ_INSERT_TAIL(&sc->vif_list, arvif, entry); > -#ifdef notyet > - spin_unlock_bh(&ar->data_lock); > -#endif > + > ret = qwx_mac_op_update_vif_offload(sc, pdev, arvif); > if (ret) > goto err_vdev_del; > @@ -24294,19 +24229,10 @@ err_peer_del: > #endif > err_vdev_del: > qwx_mac_vdev_delete(sc, arvif); > -#ifdef notyet > - spin_lock_bh(&ar->data_lock); > -#endif > - TAILQ_REMOVE(&sc->vif_list, arvif, entry); > -#ifdef notyet > - spin_unlock_bh(&ar->data_lock); > -#endif > - > err: > #ifdef notyet > mutex_unlock(&ar->conf_mutex); > #endif > - qwx_vif_free(sc, arvif); > return ret; > } > > @@ -26096,18 +26022,13 @@ int > qwx_scan(struct qwx_softc *sc, int bgscan) > { > struct ieee80211com *ic = &sc->sc_ic; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); > + struct qwx_vif *arvif = &sc->sc_vif; > struct scan_req_params *arg = NULL; > struct ieee80211_channel *chan, *lastc; > int ret = 0, num_channels, i; > uint32_t scan_timeout; > int scan_2ghz = 1, scan_5ghz = 1; > > - if (arvif == NULL) { > - printf("%s: no vdev found\n", sc->sc_dev.dv_xname); > - return EINVAL; > - } > - > /* > * TODO Will we need separate scan iterations on devices with > * multiple radios? > @@ -26356,7 +26277,7 @@ qwx_bgscan_done_task(void *arg) > { > struct qwx_softc *sc = arg; > struct qwx_dp *dp = &sc->dp; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > struct ieee80211com *ic = &sc->sc_ic; > struct ifnet *ifp = &ic->ic_if; > struct ieee80211_node *ni = ic->ic_bss; > @@ -26589,16 +26510,10 @@ qwx_auth(struct qwx_softc *sc) > struct ieee80211com *ic = &sc->sc_ic; > struct ieee80211_node *ni = ic->ic_bss; > uint32_t param_id; > - struct qwx_vif *arvif; > + struct qwx_vif *arvif = &sc->sc_vif; > struct qwx_pdev *pdev; > int ret; > > - arvif = TAILQ_FIRST(&sc->vif_list); > - if (arvif == NULL) { > - printf("%s: no vdev found\n", sc->sc_dev.dv_xname); > - return EINVAL; > - } > - > pdev = qwx_get_pdev_for_chan(sc, ni->ni_chan); > if (pdev == NULL) { > printf("%s: no pdev found for channel %d\n", > @@ -26641,7 +26556,7 @@ qwx_deauth(struct qwx_softc *sc) > struct ieee80211com *ic = &sc->sc_ic; > struct ieee80211_node *ni = ic->ic_bss; > struct qwx_node *nq = (struct qwx_node *)ni; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > struct ath11k_peer *peer; > int ret; > @@ -26946,7 +26861,7 @@ qwx_updatechan(struct ieee80211com *ic) > { > struct ifnet *ifp = &ic->ic_if; > struct qwx_softc *sc = ifp->if_softc; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); > + struct qwx_vif *arvif = &sc->sc_vif; > struct ieee80211_node *ni = ic->ic_bss; > struct qwx_node *nq = (struct qwx_node *)ic->ic_bss; > int pdev_id = 0; /* TODO: derive pdev ID somehow? */ > @@ -27034,7 +26949,7 @@ qwx_rx_agg_start(struct qwx_softc *sc, struct ieee8021 > uint16_t ssn, uint16_t winsize) > { > struct ieee80211com *ic = &sc->sc_ic; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > enum hal_pn_type pn_type; > > @@ -27055,7 +26970,7 @@ void > qwx_rx_agg_stop(struct qwx_softc *sc, struct ieee80211_node *ni, uint8_t tid, > uint16_t ssn, uint16_t winsize, int timeout_val, int start) > { > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > struct qwx_node *nq = (struct qwx_node *)ni; > struct ath11k_peer *peer; > @@ -27174,7 +27089,7 @@ qwx_assoc(struct qwx_softc *sc) > struct ieee80211com *ic = &sc->sc_ic; > struct ieee80211_node *ni = ic->ic_bss; > struct qwx_node *nq = (struct qwx_node *)ni; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > struct peer_assoc_params peer_arg; > int ret; > @@ -27232,7 +27147,7 @@ qwx_run(struct qwx_softc *sc) > struct ieee80211com *ic = &sc->sc_ic; > struct ieee80211_node *ni = ic->ic_bss; > struct qwx_node *nq = (struct qwx_node *)ni; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > struct peer_assoc_params peer_arg; > int ret; > @@ -27309,7 +27224,7 @@ int > qwx_run_stop(struct qwx_softc *sc) > { > struct ieee80211com *ic = &sc->sc_ic; > - struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + struct qwx_vif *arvif = &sc->sc_vif; > uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ > struct ieee80211_node *ni = ic->ic_bss; > struct qwx_node *nq = (void *)ni; > @@ -27377,9 +27292,12 @@ qwx_attach(struct qwx_softc *sc) > for (i = 0; i < nitems(sc->pdevs); i++) > sc->pdevs[i].sc = sc; > > - TAILQ_INIT(&sc->vif_list); > TAILQ_INIT(&sc->peers); > > + error = qwx_vif_alloc(sc); > + if (error) > + return error; > + > error = qwx_init(ifp); > if (error) > return error; > @@ -27395,6 +27313,9 @@ qwx_detach(struct qwx_softc *sc) > { > qwx_free_peers(sc); > > + qwx_vif_purge(sc); > + qwx_vif_free(sc); > + > if (sc->fwmem) { > qwx_dmamem_free(sc->sc_dmat, sc->fwmem); > sc->fwmem = NULL; > blob - e4ae6b82503480d3a351b05f9244868e1a852cf6 > blob + 73001394b0c3bcd13e4075db70d647b0c5a0f645 > --- sys/dev/ic/qwxvar.h > +++ sys/dev/ic/qwxvar.h > @@ -1668,11 +1668,8 @@ struct qwx_vif { > uint8_t hal_addr_search_flags; > uint8_t search_type; > > - struct qwx_softc *sc; > - > uint16_t tx_seq_no; > struct wmi_wmm_params_all_arg wmm_params; > - TAILQ_ENTRY(qwx_vif) entry; > union { > struct { > uint32_t uapsd; > @@ -1720,8 +1717,6 @@ struct qwx_vif { > struct qwx_txmgmt_queue txmgmt; > }; > > -TAILQ_HEAD(qwx_vif_list, qwx_vif); > - > struct qwx_survey_info { > int8_t noise; > uint64_t time; > @@ -1953,7 +1948,7 @@ struct qwx_softc { > > uint32_t pktlog_defs_checksum; > > - struct qwx_vif_list vif_list; > + struct qwx_vif sc_vif; > struct qwx_pdev pdevs[MAX_RADIOS]; > struct { > enum WMI_HOST_WLAN_BAND supported_bands; > >