diff options
Diffstat (limited to 'sys/dev/usb/wlan/if_upgt.c')
-rw-r--r-- | sys/dev/usb/wlan/if_upgt.c | 323 |
1 files changed, 211 insertions, 112 deletions
diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c index b882fe3..a2e493e 100644 --- a/sys/dev/usb/wlan/if_upgt.c +++ b/sys/dev/usb/wlan/if_upgt.c @@ -128,10 +128,10 @@ static void upgt_eeprom_parse_freq4(struct upgt_softc *, uint8_t *, int); static void upgt_eeprom_parse_freq6(struct upgt_softc *, uint8_t *, int); static uint32_t upgt_chksum_le(const uint32_t *, size_t); static void upgt_tx_done(struct upgt_softc *, uint8_t *); -static void upgt_init(struct upgt_softc *); -static void upgt_parent(struct ieee80211com *); -static int upgt_transmit(struct ieee80211com *, struct mbuf *); -static void upgt_start(struct upgt_softc *); +static void upgt_init(void *); +static void upgt_init_locked(struct upgt_softc *); +static int upgt_ioctl(struct ifnet *, u_long, caddr_t); +static void upgt_start(struct ifnet *); static int upgt_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void upgt_scan_start(struct ieee80211com *); @@ -240,11 +240,12 @@ upgt_match(device_t dev) static int upgt_attach(device_t dev) { + int error; + struct ieee80211com *ic; + struct ifnet *ifp; struct upgt_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; struct usb_attach_arg *uaa = device_get_ivars(dev); uint8_t bands, iface_index = UPGT_IFACE_INDEX; - int error; sc->sc_dev = dev; sc->sc_udev = uaa->device; @@ -257,7 +258,6 @@ upgt_attach(device_t dev) MTX_DEF); callout_init(&sc->sc_led_ch, 0); callout_init(&sc->sc_watchdog_ch, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, upgt_config, UPGT_N_XFERS, sc, &sc->sc_mtx); @@ -280,20 +280,26 @@ upgt_attach(device_t dev) if (error) goto fail3; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + goto fail4; + } + /* Initialize the device. */ error = upgt_device_reset(sc); if (error) - goto fail4; + goto fail5; /* Verify the firmware. */ error = upgt_fw_verify(sc); if (error) - goto fail4; + goto fail5; /* Calculate device memory space. */ if (sc->sc_memaddr_frame_start == 0 || sc->sc_memaddr_frame_end == 0) { device_printf(dev, "could not find memory space addresses on FW\n"); error = EIO; - goto fail4; + goto fail5; } sc->sc_memaddr_frame_end -= UPGT_MEMSIZE_RX + 1; sc->sc_memaddr_rx_start = sc->sc_memaddr_frame_end + 1; @@ -310,19 +316,31 @@ upgt_attach(device_t dev) /* Load the firmware. */ error = upgt_fw_load(sc); if (error) - goto fail4; + goto fail5; /* Read the whole EEPROM content and parse it. */ error = upgt_eeprom_read(sc); if (error) - goto fail4; + goto fail5; error = upgt_eeprom_parse(sc); if (error) - goto fail4; + goto fail5; /* all works related with the device have done here. */ upgt_abort_xfers(sc); + /* Setup the 802.11 device. */ + ifp->if_softc = sc; + if_initname(ifp, "upgt", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = upgt_init; + ifp->if_ioctl = upgt_ioctl; + ifp->if_start = upgt_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + IFQ_SET_READY(&ifp->if_snd); + + ic = ifp->if_l2com; + ic->ic_ifp = ifp; ic->ic_softc = sc; ic->ic_name = device_get_nameunit(dev); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -342,16 +360,15 @@ upgt_attach(device_t dev) setbit(&bands, IEEE80211_MODE_11G); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_myaddr); ic->ic_raw_xmit = upgt_raw_xmit; ic->ic_scan_start = upgt_scan_start; ic->ic_scan_end = upgt_scan_end; ic->ic_set_channel = upgt_set_channel; + ic->ic_vap_create = upgt_vap_create; ic->ic_vap_delete = upgt_vap_delete; ic->ic_update_mcast = upgt_update_mcast; - ic->ic_transmit = upgt_transmit; - ic->ic_parent = upgt_parent; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -366,6 +383,7 @@ upgt_attach(device_t dev) return (0); +fail5: if_free(ifp); fail4: upgt_free_rx(sc); fail3: upgt_free_tx(sc); fail2: usbd_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); @@ -377,13 +395,30 @@ fail1: mtx_destroy(&sc->sc_mtx); static void upgt_txeof(struct usb_xfer *xfer, struct upgt_data *data) { + struct upgt_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; + + UPGT_ASSERT_LOCKED(sc); + /* + * Do any tx complete callback. Note this must be done before releasing + * the node reference. + */ if (data->m) { - /* XXX status? */ - ieee80211_tx_complete(data->ni, data->m, 0); + m = data->m; + if (m->m_flags & M_TXCB) { + /* XXX status? */ + ieee80211_process_callback(data->ni, m, 0); + } + m_freem(m); data->m = NULL; + } + if (data->ni) { + ieee80211_free_node(data->ni); data->ni = NULL; } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } static void @@ -427,43 +462,77 @@ upgt_get_stats(struct upgt_softc *sc) upgt_bulk_tx(sc, data_cmd); } -static void -upgt_parent(struct ieee80211com *ic) +static int +upgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct upgt_softc *sc = ic->ic_softc; + struct upgt_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error; int startall = 0; UPGT_LOCK(sc); - if (sc->sc_flags & UPGT_FLAG_DETACHED) { - UPGT_UNLOCK(sc); - return; - } - if (ic->ic_nrunning > 0) { - if (sc->sc_flags & UPGT_FLAG_INITDONE) { - if (ic->ic_allmulti > 0 || ic->ic_promisc > 0) - upgt_set_multi(sc); + error = (sc->sc_flags & UPGT_FLAG_DETACHED) ? ENXIO : 0; + UPGT_UNLOCK(sc); + if (error) + return (error); + + switch (cmd) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->sc_if_flags) & + (IFF_ALLMULTI | IFF_PROMISC)) + upgt_set_multi(sc); + } else { + upgt_init(sc); + startall = 1; + } } else { - upgt_init(sc); - startall = 1; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + upgt_stop(sc); } - } else if (sc->sc_flags & UPGT_FLAG_INITDONE) - upgt_stop(sc); - UPGT_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + sc->sc_if_flags = ifp->if_flags; + if (startall) + ieee80211_start_all(ic); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + default: + error = EINVAL; + break; + } + return error; } static void -upgt_stop(struct upgt_softc *sc) +upgt_stop_locked(struct upgt_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; UPGT_ASSERT_LOCKED(sc); - if (sc->sc_flags & UPGT_FLAG_INITDONE) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) upgt_set_macfilter(sc, IEEE80211_S_INIT); upgt_abort_xfers_locked(sc); +} + +static void +upgt_stop(struct upgt_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + + UPGT_LOCK(sc); + upgt_stop_locked(sc); + UPGT_UNLOCK(sc); + /* device down */ sc->sc_tx_timer = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); sc->sc_flags &= ~UPGT_FLAG_INITDONE; } @@ -555,18 +624,36 @@ upgt_set_led_blink(void *arg) } static void -upgt_init(struct upgt_softc *sc) +upgt_init(void *priv) +{ + struct upgt_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + UPGT_LOCK(sc); + upgt_init_locked(sc); + UPGT_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void +upgt_init_locked(struct upgt_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; UPGT_ASSERT_LOCKED(sc); - if (sc->sc_flags & UPGT_FLAG_INITDONE) - upgt_stop(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + upgt_stop_locked(sc); usbd_transfer_start(sc->sc_xfer[UPGT_BULK_RX]); (void)upgt_set_macfilter(sc, IEEE80211_S_SCAN); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->sc_flags |= UPGT_FLAG_INITDONE; callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); @@ -575,12 +662,14 @@ upgt_init(struct upgt_softc *sc) static int upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni; struct upgt_data *data_cmd; struct upgt_lmac_mem *mem; struct upgt_lmac_filter *filter; + uint8_t broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; UPGT_ASSERT_LOCKED(sc); @@ -620,11 +709,10 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) case IEEE80211_S_SCAN: DPRINTF(sc, UPGT_DEBUG_STATE, "set MAC filter to SCAN (bssid %s)\n", - ether_sprintf(ieee80211broadcastaddr)); + ether_sprintf(broadcast)); filter->type = htole16(UPGT_FILTER_TYPE_NONE); - IEEE80211_ADDR_COPY(filter->dst, - vap ? vap->iv_myaddr : ic->ic_macaddr); - IEEE80211_ADDR_COPY(filter->src, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); + IEEE80211_ADDR_COPY(filter->src, broadcast); filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); filter->rxaddr = htole32(sc->sc_memaddr_rx_start); filter->unknown2 = htole16(UPGT_FILTER_UNKNOWN2); @@ -636,8 +724,7 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) /* XXX monitor mode isn't tested yet. */ if (vap->iv_opmode == IEEE80211_M_MONITOR) { filter->type = htole16(UPGT_FILTER_TYPE_MONITOR); - IEEE80211_ADDR_COPY(filter->dst, - vap ? vap->iv_myaddr : ic->ic_macaddr); + IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); filter->unknown1 = htole16(UPGT_FILTER_MONITOR_UNKNOWN1); filter->rxaddr = htole32(sc->sc_memaddr_rx_start); @@ -649,8 +736,7 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) "set MAC filter to RUN (bssid %s)\n", ether_sprintf(ni->ni_bssid)); filter->type = htole16(UPGT_FILTER_TYPE_STA); - IEEE80211_ADDR_COPY(filter->dst, - vap ? vap->iv_myaddr : ic->ic_macaddr); + IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); filter->rxaddr = htole32(sc->sc_memaddr_rx_start); @@ -679,7 +765,8 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) static void upgt_setup_rates(struct ieee80211vap *vap, struct ieee80211com *ic) { - struct upgt_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct upgt_softc *sc = ifp->if_softc; const struct ieee80211_txparam *tp; /* @@ -726,48 +813,39 @@ upgt_setup_rates(struct ieee80211vap *vap, struct ieee80211com *ic) static void upgt_set_multi(void *arg) { + struct upgt_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; - /* XXX don't know how to set a device. Lack of docs. */ -} - -static int -upgt_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct upgt_softc *sc = ic->ic_softc; - int error; - - UPGT_LOCK(sc); - if ((sc->sc_flags & UPGT_FLAG_INITDONE) == 0) { - UPGT_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - UPGT_UNLOCK(sc); - return (error); - } - upgt_start(sc); - UPGT_UNLOCK(sc); + if (!(ifp->if_flags & IFF_UP)) + return; - return (0); + /* + * XXX don't know how to set a device. Lack of docs. Just try to set + * IFF_ALLMULTI flag here. + */ + ifp->if_flags |= IFF_ALLMULTI; } static void -upgt_start(struct upgt_softc *sc) +upgt_start(struct ifnet *ifp) { + struct upgt_softc *sc = ifp->if_softc; struct upgt_data *data_tx; struct ieee80211_node *ni; struct mbuf *m; - UPGT_ASSERT_LOCKED(sc); - - if ((sc->sc_flags & UPGT_FLAG_INITDONE) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + UPGT_LOCK(sc); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + data_tx = upgt_gettxbuf(sc); if (data_tx == NULL) { - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); break; } @@ -775,15 +853,15 @@ upgt_start(struct upgt_softc *sc) m->m_pkthdr.rcvif = NULL; if (upgt_tx_start(sc, m, ni, data_tx) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); UPGT_STAT_INC(sc, st_tx_inactive); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } sc->sc_tx_timer = 5; } + UPGT_UNLOCK(sc); } static int @@ -791,18 +869,18 @@ upgt_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct upgt_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct upgt_softc *sc = ifp->if_softc; struct upgt_data *data_tx = NULL; - UPGT_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & UPGT_FLAG_INITDONE)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { m_freem(m); ieee80211_free_node(ni); - UPGT_UNLOCK(sc); return ENETDOWN; } + UPGT_LOCK(sc); data_tx = upgt_gettxbuf(sc); if (data_tx == NULL) { ieee80211_free_node(ni); @@ -815,6 +893,7 @@ upgt_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); UPGT_STAT_INC(sc, st_tx_inactive); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); UPGT_UNLOCK(sc); return (EIO); } @@ -828,13 +907,13 @@ static void upgt_watchdog(void *arg) { struct upgt_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { device_printf(sc->sc_dev, "watchdog timeout\n"); - /* upgt_init(sc); XXX needs a process context ? */ - counter_u64_add(ic->ic_oerrors, 1); + /* upgt_init(ifp); XXX needs a process context ? */ + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return; } callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); @@ -871,7 +950,7 @@ upgt_scan_end(struct ieee80211com *ic) static void upgt_set_channel(struct ieee80211com *ic) { - struct upgt_softc *sc = ic->ic_softc; + struct upgt_softc *sc = ic->ic_ifp->if_softc; UPGT_LOCK(sc); upgt_set_chan(sc, ic->ic_curchan); @@ -881,7 +960,8 @@ upgt_set_channel(struct ieee80211com *ic) static void upgt_set_chan(struct upgt_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct upgt_data *data_cmd; struct upgt_lmac_mem *mem; struct upgt_lmac_channel *chan; @@ -964,7 +1044,7 @@ upgt_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, /* enable s/w bmiss handling for sta mode */ if (ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) { /* out of memory */ free(uvp, M_80211_VAP); return (NULL); @@ -979,7 +1059,7 @@ upgt_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -989,7 +1069,7 @@ upgt_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct upgt_vap *uvp = UPGT_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct upgt_softc *sc = ic->ic_softc; + struct upgt_softc *sc = ic->ic_ifp->if_softc; /* do it in a process context */ sc->sc_state = nstate; @@ -1045,7 +1125,6 @@ upgt_update_mcast(struct ieee80211com *ic) static int upgt_eeprom_parse(struct upgt_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; struct upgt_eeprom_header *eeprom_header; struct upgt_eeprom_option *eeprom_option; uint16_t option_len; @@ -1090,8 +1169,7 @@ upgt_eeprom_parse(struct upgt_softc *sc) DPRINTF(sc, UPGT_DEBUG_FW, "EEPROM mac len=%d\n", option_len); - IEEE80211_ADDR_COPY(ic->ic_macaddr, - eeprom_option->data); + IEEE80211_ADDR_COPY(sc->sc_myaddr, eeprom_option->data); break; case UPGT_EEPROM_TYPE_HWRX: DPRINTF(sc, UPGT_DEBUG_FW, @@ -1440,7 +1518,8 @@ upgt_chksum_le(const uint32_t *buf, size_t size) static struct mbuf * upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct upgt_lmac_rx_desc *rxdesc; struct mbuf *m; @@ -1448,7 +1527,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) * don't pass packets to the ieee80211 framework if the driver isn't * RUNNING. */ - if (!(sc->sc_flags & UPGT_FLAG_INITDONE)) + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) return (NULL); /* access RX packet descriptor */ @@ -1466,6 +1545,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) memcpy(mtod(m, char *), rxdesc->data, pkglen); /* trim FCS */ m->m_len = m->m_pkthdr.len = pkglen - IEEE80211_CRC_LEN; + m->m_pkthdr.rcvif = ifp; if (ieee80211_radiotap_active(ic)) { struct upgt_rx_radiotap_header *tap = &sc->sc_rxtap; @@ -1474,6 +1554,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) tap->wr_rate = upgt_rx_rate(sc, rxdesc->rate); tap->wr_antsignal = rxdesc->rssi; } + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); DPRINTF(sc, UPGT_DEBUG_RX_PROC, "%s: RX done\n", __func__); *rssi = rxdesc->rssi; @@ -1483,7 +1564,8 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) static uint8_t upgt_rx_rate(struct upgt_softc *sc, const int rate) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static const uint8_t cck_upgt2rate[4] = { 2, 4, 11, 22 }; static const uint8_t ofdm_upgt2rate[12] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; @@ -1502,6 +1584,7 @@ upgt_rx_rate(struct upgt_softc *sc, const int rate) static void upgt_tx_done(struct upgt_softc *sc, uint8_t *data) { + struct ifnet *ifp = sc->sc_ifp; struct upgt_lmac_tx_done_desc *desc; int i, freed = 0; @@ -1530,9 +1613,10 @@ upgt_tx_done(struct upgt_softc *sc, uint8_t *data) } if (freed != 0) { - UPGT_UNLOCK(sc); sc->sc_tx_timer = 0; - upgt_start(sc); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + UPGT_UNLOCK(sc); + upgt_start(ifp); UPGT_LOCK(sc); } } @@ -1938,7 +2022,8 @@ static int upgt_detach(device_t dev) { struct upgt_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; unsigned int x; /* @@ -1954,9 +2039,9 @@ upgt_detach(device_t dev) STAILQ_INIT(&sc->sc_rx_active); STAILQ_INIT(&sc->sc_rx_inactive); + UPGT_UNLOCK(sc); upgt_stop(sc); - UPGT_UNLOCK(sc); callout_drain(&sc->sc_led_ch); callout_drain(&sc->sc_watchdog_ch); @@ -1975,7 +2060,7 @@ upgt_detach(device_t dev) usbd_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + if_free(ifp); mtx_destroy(&sc->sc_mtx); return (0); @@ -2083,8 +2168,12 @@ upgt_getbuf(struct upgt_softc *sc) UPGT_ASSERT_LOCKED(sc); bf = _upgt_getbuf(sc); - if (bf == NULL) + if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: stop queue\n", __func__); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } return (bf); } @@ -2102,10 +2191,14 @@ upgt_gettxbuf(struct upgt_softc *sc) bf->addr = upgt_mem_alloc(sc); if (bf->addr == 0) { + struct ifnet *ifp = sc->sc_ifp; + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: no free prism memory!\n", __func__); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); UPGT_STAT_INC(sc, st_tx_inactive); + if (!(ifp->if_drv_flags & IFF_DRV_OACTIVE)) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; return (NULL); } return (bf); @@ -2119,6 +2212,7 @@ upgt_tx_start(struct upgt_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int error = 0, len; struct ieee80211_frame *wh; struct ieee80211_key *k; + struct ifnet *ifp = sc->sc_ifp; struct upgt_lmac_mem *mem; struct upgt_lmac_tx_desc *txdesc; @@ -2201,7 +2295,7 @@ done: * will stall. It's strange, but it works, so we keep reading * the statistics here. *shrug* */ - if (!(vap->iv_ifp->if_get_counter(vap->iv_ifp, IFCOUNTER_OPACKETS) % + if (!(ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS) % UPGT_TX_STAT_INTERVAL)) upgt_get_stats(sc); @@ -2212,7 +2306,8 @@ static void upgt_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct upgt_softc *sc = usbd_xfer_softc(xfer); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct mbuf *m = NULL; @@ -2260,8 +2355,10 @@ setup: (void) ieee80211_input_all(ic, m, rssi, nf); m = NULL; } + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) + upgt_start(ifp); UPGT_LOCK(sc); - upgt_start(sc); break; default: /* needs it to the inactive queue due to a error. */ @@ -2272,7 +2369,7 @@ setup: } if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto setup; } break; @@ -2283,6 +2380,7 @@ static void upgt_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) { struct upgt_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct upgt_data *data; UPGT_ASSERT_LOCKED(sc); @@ -2312,17 +2410,18 @@ setup: usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); usbd_transfer_submit(xfer); - upgt_start(sc); + UPGT_UNLOCK(sc); + upgt_start(ifp); + UPGT_LOCK(sc); break; default: data = STAILQ_FIRST(&sc->sc_tx_active); if (data == NULL) goto setup; if (data->ni != NULL) { - if_inc_counter(data->ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(data->ni); data->ni = NULL; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); |