diff options
Diffstat (limited to 'sys/dev/usb/wlan/if_urtwn.c')
-rw-r--r-- | sys/dev/usb/wlan/if_urtwn.c | 282 |
1 files changed, 186 insertions, 96 deletions
diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/usb/wlan/if_urtwn.c index 457a885..6b712b3 100644 --- a/sys/dev/usb/wlan/if_urtwn.c +++ b/sys/dev/usb/wlan/if_urtwn.c @@ -169,8 +169,8 @@ static device_detach_t urtwn_detach; static usb_callback_t urtwn_bulk_tx_callback; static usb_callback_t urtwn_bulk_rx_callback; -static usb_error_t urtwn_do_request(struct urtwn_softc *, - struct usb_device_request *, void *); +static usb_error_t urtwn_do_request(struct urtwn_softc *sc, + struct usb_device_request *req, void *data); static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, const char [IFNAMSIZ], int, enum ieee80211_opmode, int, const uint8_t [IEEE80211_ADDR_LEN], @@ -228,9 +228,10 @@ static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); static int urtwn_tx_start(struct urtwn_softc *, struct ieee80211_node *, struct mbuf *, struct urtwn_data *); -static int urtwn_transmit(struct ieee80211com *, struct mbuf *); -static void urtwn_start(struct urtwn_softc *); -static void urtwn_parent(struct ieee80211com *); +static void urtwn_start(struct ifnet *); +static void urtwn_start_locked(struct ifnet *, + struct urtwn_softc *); +static int urtwn_ioctl(struct ifnet *, u_long, caddr_t); static int urtwn_r92c_power_on(struct urtwn_softc *); static int urtwn_r88e_power_on(struct urtwn_softc *); static int urtwn_llt_init(struct urtwn_softc *); @@ -268,8 +269,10 @@ static void urtwn_set_chan(struct urtwn_softc *, static void urtwn_update_mcast(struct ieee80211com *); static void urtwn_iq_calib(struct urtwn_softc *); static void urtwn_lc_calib(struct urtwn_softc *); -static void urtwn_init(struct urtwn_softc *); -static void urtwn_stop(struct urtwn_softc *); +static void urtwn_init(void *); +static void urtwn_init_locked(void *); +static void urtwn_stop(struct ifnet *); +static void urtwn_stop_locked(struct ifnet *); static void urtwn_abort_xfers(struct urtwn_softc *); static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); @@ -365,7 +368,8 @@ urtwn_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); struct urtwn_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; uint8_t iface_index, bands; int error; @@ -378,7 +382,6 @@ urtwn_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); callout_init(&sc->sc_watchdog_ch, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = URTWN_IFACE_INDEX; error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, @@ -421,6 +424,24 @@ urtwn_attach(device_t self) URTWN_UNLOCK(sc); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + goto detach; + } + ic = ifp->if_l2com; + + ifp->if_softc = sc; + if_initname(ifp, "urtwn", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = urtwn_init; + ifp->if_ioctl = urtwn_ioctl; + ifp->if_start = urtwn_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + ic->ic_ifp = ifp; ic->ic_softc = sc; ic->ic_name = device_get_nameunit(self); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -441,13 +462,12 @@ urtwn_attach(device_t self) setbit(&bands, IEEE80211_MODE_11G); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_bssid); ic->ic_raw_xmit = urtwn_raw_xmit; ic->ic_scan_start = urtwn_scan_start; ic->ic_scan_end = urtwn_scan_end; ic->ic_set_channel = urtwn_set_channel; - ic->ic_transmit = urtwn_transmit; - ic->ic_parent = urtwn_parent; + ic->ic_vap_create = urtwn_vap_create; ic->ic_vap_delete = urtwn_vap_delete; ic->ic_update_mcast = urtwn_update_mcast; @@ -471,15 +491,17 @@ static int urtwn_detach(device_t self) { struct urtwn_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; unsigned int x; /* Prevent further ioctls. */ URTWN_LOCK(sc); sc->sc_flags |= URTWN_DETACHED; - urtwn_stop(sc); URTWN_UNLOCK(sc); + urtwn_stop(ifp); + callout_drain(&sc->sc_watchdog_ch); /* Prevent further allocations from RX/TX data lists. */ @@ -505,7 +527,8 @@ urtwn_detach(device_t self) /* stop all USB transfers */ usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + + if_free(ifp); mtx_destroy(&sc->sc_mtx); return (0); @@ -576,12 +599,15 @@ urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return (NULL); - uvp = malloc(sizeof(struct urtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); + uvp = (struct urtwn_vap *) malloc(sizeof(struct urtwn_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (uvp == NULL) + return (NULL); vap = &uvp->vap; /* 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); @@ -593,7 +619,7 @@ urtwn_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); } @@ -610,7 +636,8 @@ urtwn_vap_delete(struct ieee80211vap *vap) static struct mbuf * urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_frame *wh; struct mbuf *m; struct r92c_rx_stat *stat; @@ -623,7 +650,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) * don't pass packets to the ieee80211 framework if the driver isn't * RUNNING. */ - if (!(sc->sc_flags & URTWN_RUNNING)) + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) return (NULL); stat = (struct r92c_rx_stat *)buf; @@ -635,11 +662,11 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) * This should not happen since we setup our Rx filter * to not receive these frames. */ - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } if (pktlen < sizeof(*wh) || pktlen > MCLBYTES) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } @@ -668,6 +695,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) } /* Finalize mbuf. */ + m->m_pkthdr.rcvif = ifp; wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); memcpy(mtod(m, uint8_t *), wh, pktlen); m->m_pkthdr.len = m->m_len = pktlen; @@ -713,7 +741,7 @@ urtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, int8_t *nf) { struct urtwn_softc *sc = data->sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; struct r92c_rx_stat *stat; struct mbuf *m, *m0 = NULL, *prevm = NULL; uint32_t rxdw0; @@ -723,7 +751,7 @@ urtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, usbd_xfer_status(xfer, &len, NULL, NULL, NULL); if (len < sizeof(*stat)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } @@ -774,7 +802,8 @@ static void urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct urtwn_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, *next; @@ -837,7 +866,7 @@ tr_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 tr_setup; } break; @@ -848,19 +877,38 @@ static void urtwn_txeof(struct usb_xfer *xfer, struct urtwn_data *data) { struct urtwn_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; URTWN_ASSERT_LOCKED(sc); - /* XXX status? */ - ieee80211_tx_complete(data->ni, data->m, 0); - data->ni = NULL; - data->m = NULL; + + /* + * Do any tx complete callback. Note this must be done before releasing + * the node reference. + */ + if (data->m) { + 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; + } sc->sc_txtimer = 0; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static void urtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) { struct urtwn_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct urtwn_data *data; URTWN_ASSERT_LOCKED(sc); @@ -885,17 +933,16 @@ tr_setup: STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); usbd_transfer_submit(xfer); - urtwn_start(sc); + urtwn_start_locked(ifp, sc); break; default: data = STAILQ_FIRST(&sc->sc_tx_active); if (data == NULL) goto tr_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); @@ -928,8 +975,11 @@ urtwn_getbuf(struct urtwn_softc *sc) URTWN_ASSERT_LOCKED(sc); bf = _urtwn_getbuf(sc); - if (bf == NULL) + if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; DPRINTF("%s: stop queue\n", __func__); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } return (bf); } @@ -1252,7 +1302,7 @@ urtwn_read_rom(struct urtwn_softc *sc) sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); DPRINTF("regulatory type=%d\n", sc->regulatory); - IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); + IEEE80211_ADDR_COPY(sc->sc_bssid, rom->macaddr); sc->sc_rf_write = urtwn_r92c_rf_write; sc->sc_power_on = urtwn_r92c_power_on; @@ -1313,7 +1363,7 @@ urtwn_r88e_read_rom(struct urtwn_softc *sc) if (sc->ofdm_tx_pwr_diff & 0x08) sc->ofdm_tx_pwr_diff |= 0xf0; sc->regulatory = MS(sc->r88e_rom[0xc1], R92C_ROM_RF1_REGULATORY); - IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, &sc->r88e_rom[0xd7]); + IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->r88e_rom[0xd7]); sc->sc_rf_write = urtwn_r88e_rf_write; sc->sc_power_on = urtwn_r88e_power_on; @@ -1328,7 +1378,7 @@ urtwn_ra_init(struct urtwn_softc *sc) { static const uint8_t map[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni; struct ieee80211_rateset *rs; @@ -1405,7 +1455,8 @@ urtwn_ra_init(struct urtwn_softc *sc) void urtwn_tsf_sync_enable(struct urtwn_softc *sc) { - 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 = vap->iv_bss; @@ -1462,7 +1513,7 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct urtwn_vap *uvp = URTWN_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct urtwn_softc *sc = ic->ic_softc; + struct urtwn_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; enum ieee80211_state ostate; uint32_t reg; @@ -1618,11 +1669,12 @@ static void urtwn_watchdog(void *arg) { struct urtwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; if (sc->sc_txtimer > 0) { if (--sc->sc_txtimer == 0) { device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return; } callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); @@ -1748,9 +1800,10 @@ static int urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, struct urtwn_data *data) { + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_frame *wh; struct ieee80211_key *k; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct usb_xfer *xfer; struct r92c_tx_desc *txd; @@ -1889,78 +1942,89 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni, return (0); } -static int -urtwn_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +urtwn_start(struct ifnet *ifp) { - struct urtwn_softc *sc = ic->ic_softc; - int error; + struct urtwn_softc *sc = ifp->if_softc; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; URTWN_LOCK(sc); - if ((sc->sc_flags & URTWN_RUNNING) == 0) { - URTWN_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - URTWN_UNLOCK(sc); - return (error); - } - urtwn_start(sc); + urtwn_start_locked(ifp, sc); URTWN_UNLOCK(sc); - - return (0); } static void -urtwn_start(struct urtwn_softc *sc) +urtwn_start_locked(struct ifnet *ifp, struct urtwn_softc *sc) { struct ieee80211_node *ni; struct mbuf *m; struct urtwn_data *bf; URTWN_ASSERT_LOCKED(sc); - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; bf = urtwn_getbuf(sc); if (bf == NULL) { - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); break; } ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; m->m_pkthdr.rcvif = NULL; + if (urtwn_tx_start(sc, ni, m, bf) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); ieee80211_free_node(ni); break; } + sc->sc_txtimer = 5; callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); } } -static void -urtwn_parent(struct ieee80211com *ic) +static int +urtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct urtwn_softc *sc = ic->ic_softc; - int startall = 0; + struct urtwn_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; URTWN_LOCK(sc); - if (sc->sc_flags & URTWN_DETACHED) { - URTWN_UNLOCK(sc); - return; - } - if (ic->ic_nrunning > 0) { - if ((sc->sc_flags & URTWN_RUNNING) == 0) { - urtwn_init(sc); - startall = 1; - } - } else if (sc->sc_flags & URTWN_RUNNING) - urtwn_stop(sc); + error = (sc->sc_flags & URTWN_DETACHED) ? ENXIO : 0; URTWN_UNLOCK(sc); + if (error != 0) + return (error); - if (startall) - ieee80211_start_all(ic); + switch (cmd) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + urtwn_init(ifp->if_softc); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + urtwn_stop(ifp); + } + 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 int @@ -2874,7 +2938,7 @@ urtwn_get_txpower(struct urtwn_softc *sc, int chain, struct ieee80211_channel *c, struct ieee80211_channel *extc, uint16_t power[URTWN_RIDX_COUNT]) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct r92c_rom *rom = &sc->rom; uint16_t cckpow, ofdmpow, htpow, diff, max; const struct urtwn_txpwr *base; @@ -2973,7 +3037,7 @@ urtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain, struct ieee80211_channel *c, struct ieee80211_channel *extc, uint16_t power[URTWN_RIDX_COUNT]) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint16_t cckpow, ofdmpow, bw20pow, htpow; const struct urtwn_r88e_txpwr *base; int ridx, chan, group; @@ -3070,7 +3134,7 @@ urtwn_scan_end(struct ieee80211com *ic) static void urtwn_set_channel(struct ieee80211com *ic) { - struct urtwn_softc *sc = ic->ic_softc; + struct urtwn_softc *sc = ic->ic_ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); URTWN_LOCK(sc); @@ -3092,7 +3156,7 @@ static void urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, struct ieee80211_channel *extc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint32_t reg; u_int chan; int i; @@ -3223,18 +3287,17 @@ urtwn_lc_calib(struct urtwn_softc *sc) } static void -urtwn_init(struct urtwn_softc *sc) +urtwn_init_locked(void *arg) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - uint8_t macaddr[IEEE80211_ADDR_LEN]; + struct urtwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t reg; int error; URTWN_ASSERT_LOCKED(sc); - if (sc->sc_flags & URTWN_RUNNING) - urtwn_stop(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + urtwn_stop_locked(ifp); /* Init firmware commands ring. */ sc->fwcur = 0; @@ -3277,8 +3340,8 @@ urtwn_init(struct urtwn_softc *sc) } /* Set MAC address. */ - IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); - urtwn_write_region_1(sc, R92C_MACID, macaddr, IEEE80211_ADDR_LEN); + urtwn_write_region_1(sc, R92C_MACID, IF_LLADDR(ifp), + IEEE80211_ADDR_LEN); /* Set initial network type. */ reg = urtwn_read_4(sc, R92C_CR); @@ -3402,7 +3465,8 @@ urtwn_init(struct urtwn_softc *sc) usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]); - sc->sc_flags |= URTWN_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); fail: @@ -3410,16 +3474,39 @@ fail: } static void -urtwn_stop(struct urtwn_softc *sc) +urtwn_init(void *arg) +{ + struct urtwn_softc *sc = arg; + + URTWN_LOCK(sc); + urtwn_init_locked(arg); + URTWN_UNLOCK(sc); +} + +static void +urtwn_stop_locked(struct ifnet *ifp) { + struct urtwn_softc *sc = ifp->if_softc; URTWN_ASSERT_LOCKED(sc); - sc->sc_flags &= ~URTWN_RUNNING; + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + callout_stop(&sc->sc_watchdog_ch); urtwn_abort_xfers(sc); } static void +urtwn_stop(struct ifnet *ifp) +{ + struct urtwn_softc *sc = ifp->if_softc; + + URTWN_LOCK(sc); + urtwn_stop_locked(ifp); + URTWN_UNLOCK(sc); +} + +static void urtwn_abort_xfers(struct urtwn_softc *sc) { int i; @@ -3436,11 +3523,12 @@ urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct urtwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct urtwn_softc *sc = ifp->if_softc; struct urtwn_data *bf; /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & URTWN_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { m_freem(m); ieee80211_free_node(ni); return (ENETDOWN); @@ -3454,8 +3542,10 @@ urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return (ENOBUFS); } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if (urtwn_tx_start(sc, ni, m, bf) != 0) { ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); URTWN_UNLOCK(sc); return (EIO); |