Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_uath.c
Context not available. | |||||
static int uath_alloc_tx_data_list(struct uath_softc *); | static int uath_alloc_tx_data_list(struct uath_softc *); | ||||
static void uath_free_rx_data_list(struct uath_softc *); | static void uath_free_rx_data_list(struct uath_softc *); | ||||
static void uath_free_tx_data_list(struct uath_softc *); | static void uath_free_tx_data_list(struct uath_softc *); | ||||
static int uath_init_locked(void *); | static int uath_init(struct uath_softc *); | ||||
static void uath_init(void *); | static void uath_stop(struct uath_softc *); | ||||
static void uath_stop_locked(struct ifnet *); | static void uath_parent(struct ieee80211com *); | ||||
static void uath_stop(struct ifnet *); | static int uath_transmit(struct ieee80211com *, struct mbuf *); | ||||
static int uath_ioctl(struct ifnet *, u_long, caddr_t); | static void uath_start(struct uath_softc *); | ||||
static void uath_start(struct ifnet *); | |||||
static int uath_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int uath_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void uath_scan_start(struct ieee80211com *); | static void uath_scan_start(struct ieee80211com *); | ||||
Context not available. | |||||
{ | { | ||||
struct uath_softc *sc = device_get_softc(dev); | struct uath_softc *sc = device_get_softc(dev); | ||||
struct usb_attach_arg *uaa = device_get_ivars(dev); | struct usb_attach_arg *uaa = device_get_ivars(dev); | ||||
struct ieee80211com *ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ifnet *ifp; | |||||
uint8_t bands, iface_index = UATH_IFACE_INDEX; /* XXX */ | uint8_t bands, iface_index = UATH_IFACE_INDEX; /* XXX */ | ||||
usb_error_t error; | usb_error_t error; | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
sc->sc_udev = uaa->device; | sc->sc_udev = uaa->device; | ||||
Context not available. | |||||
MTX_DEF); | MTX_DEF); | ||||
callout_init(&sc->stat_ch, 0); | callout_init(&sc->stat_ch, 0); | ||||
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, | error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, | ||||
uath_usbconfig, UATH_N_XFERS, sc, &sc->sc_mtx); | uath_usbconfig, UATH_N_XFERS, sc, &sc->sc_mtx); | ||||
Context not available. | |||||
error = uath_host_available(sc); | error = uath_host_available(sc); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not initialize adapter\n"); | device_printf(sc->sc_dev, "could not initialize adapter\n"); | ||||
goto fail3; | goto fail2; | ||||
} | } | ||||
error = uath_get_devcap(sc); | error = uath_get_devcap(sc); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"could not get device capabilities\n"); | "could not get device capabilities\n"); | ||||
goto fail3; | goto fail2; | ||||
} | } | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
Context not available. | |||||
/* Create device sysctl node. */ | /* Create device sysctl node. */ | ||||
uath_sysctl_node(sc); | uath_sysctl_node(sc); | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(sc->sc_dev, "can not allocate ifnet\n"); | |||||
error = ENXIO; | |||||
goto fail2; | |||||
} | |||||
UATH_LOCK(sc); | UATH_LOCK(sc); | ||||
error = uath_get_devstatus(sc, macaddr); | error = uath_get_devstatus(sc, ic->ic_macaddr); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not get device status\n"); | device_printf(sc->sc_dev, "could not get device status\n"); | ||||
goto fail4; | goto fail2; | ||||
} | } | ||||
/* | /* | ||||
Context not available. | |||||
error = uath_alloc_rx_data_list(sc); | error = uath_alloc_rx_data_list(sc); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not allocate Rx data list\n"); | device_printf(sc->sc_dev, "could not allocate Rx data list\n"); | ||||
goto fail4; | goto fail2; | ||||
} | } | ||||
error = uath_alloc_tx_data_list(sc); | error = uath_alloc_tx_data_list(sc); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not allocate Tx data list\n"); | device_printf(sc->sc_dev, "could not allocate Tx data list\n"); | ||||
goto fail4; | goto fail2; | ||||
} | } | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
ifp->if_softc = sc; | |||||
if_initname(ifp, "uath", device_get_unit(sc->sc_dev)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = uath_init; | |||||
ifp->if_ioctl = uath_ioctl; | |||||
ifp->if_start = uath_start; | |||||
/* XXX UATH_TX_DATA_LIST_COUNT */ | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ic = ifp->if_l2com; | |||||
ic->ic_ifp = ifp; | |||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = device_get_nameunit(dev); | ic->ic_name = device_get_nameunit(dev); | ||||
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ||||
Context not available. | |||||
/* XXX turbo */ | /* XXX turbo */ | ||||
ieee80211_init_channels(ic, NULL, &bands); | ieee80211_init_channels(ic, NULL, &bands); | ||||
ieee80211_ifattach(ic, macaddr); | ieee80211_ifattach(ic); | ||||
ic->ic_raw_xmit = uath_raw_xmit; | ic->ic_raw_xmit = uath_raw_xmit; | ||||
ic->ic_scan_start = uath_scan_start; | ic->ic_scan_start = uath_scan_start; | ||||
ic->ic_scan_end = uath_scan_end; | ic->ic_scan_end = uath_scan_end; | ||||
ic->ic_set_channel = uath_set_channel; | ic->ic_set_channel = uath_set_channel; | ||||
ic->ic_vap_create = uath_vap_create; | ic->ic_vap_create = uath_vap_create; | ||||
ic->ic_vap_delete = uath_vap_delete; | ic->ic_vap_delete = uath_vap_delete; | ||||
ic->ic_update_mcast = uath_update_mcast; | ic->ic_update_mcast = uath_update_mcast; | ||||
ic->ic_update_promisc = uath_update_promisc; | ic->ic_update_promisc = uath_update_promisc; | ||||
ic->ic_transmit = uath_transmit; | |||||
ic->ic_parent = uath_parent; | |||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | ||||
Context not available. | |||||
return (0); | return (0); | ||||
fail4: if_free(ifp); | fail2: UATH_UNLOCK(sc); | ||||
fail3: UATH_UNLOCK(sc); | uath_free_cmd_list(sc, sc->sc_cmd); | ||||
fail2: uath_free_cmd_list(sc, sc->sc_cmd); | |||||
fail1: usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); | fail1: usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); | ||||
fail: | fail: | ||||
return (error); | return (error); | ||||
Context not available. | |||||
uath_detach(device_t dev) | uath_detach(device_t dev) | ||||
{ | { | ||||
struct uath_softc *sc = device_get_softc(dev); | struct uath_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
unsigned int x; | unsigned int x; | ||||
/* | /* | ||||
Context not available. | |||||
STAILQ_INIT(&sc->sc_cmd_pending); | STAILQ_INIT(&sc->sc_cmd_pending); | ||||
STAILQ_INIT(&sc->sc_cmd_waiting); | STAILQ_INIT(&sc->sc_cmd_waiting); | ||||
STAILQ_INIT(&sc->sc_cmd_inactive); | STAILQ_INIT(&sc->sc_cmd_inactive); | ||||
uath_stop(sc); | |||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
uath_stop(ifp); | |||||
callout_drain(&sc->stat_ch); | callout_drain(&sc->stat_ch); | ||||
callout_drain(&sc->watchdog_ch); | callout_drain(&sc->watchdog_ch); | ||||
Context not available. | |||||
usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); | usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
if_free(ifp); | mbufq_drain(&sc->sc_snd); | ||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
return (0); | return (0); | ||||
} | } | ||||
Context not available. | |||||
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | ||||
return (NULL); | return (NULL); | ||||
uvp = (struct uath_vap *) malloc(sizeof(struct uath_vap), | uvp = malloc(sizeof(struct uath_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (uvp == NULL) | |||||
return (NULL); | |||||
vap = &uvp->vap; | vap = &uvp->vap; | ||||
/* enable s/w bmiss handling for sta mode */ | /* enable s/w bmiss handling for sta mode */ | ||||
if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | ||||
flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) { | flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { | ||||
/* out of memory */ | /* out of memory */ | ||||
free(uvp, M_80211_VAP); | free(uvp, M_80211_VAP); | ||||
return (NULL); | return (NULL); | ||||
Context not available. | |||||
/* complete setup */ | /* complete setup */ | ||||
ieee80211_vap_attach(vap, ieee80211_media_change, | ieee80211_vap_attach(vap, ieee80211_media_change, | ||||
ieee80211_media_status); | ieee80211_media_status, mac); | ||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return (vap); | return (vap); | ||||
} | } | ||||
Context not available. | |||||
} | } | ||||
static int | static int | ||||
uath_init_locked(void *arg) | uath_init(struct uath_softc *sc) | ||||
{ | { | ||||
struct uath_softc *sc = arg; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint32_t val; | uint32_t val; | ||||
int error; | int error; | ||||
UATH_ASSERT_LOCKED(sc); | UATH_ASSERT_LOCKED(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & UATH_FLAG_INITDONE) | ||||
uath_stop_locked(ifp); | uath_stop(sc); | ||||
/* reset variables */ | /* reset variables */ | ||||
sc->sc_intrx_nextnum = sc->sc_msgid = 0; | sc->sc_intrx_nextnum = sc->sc_msgid = 0; | ||||
Context not available. | |||||
uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof val, 0); | uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof val, 0); | ||||
/* set MAC address */ | /* set MAC address */ | ||||
uath_config_multi(sc, CFG_MAC_ADDR, IF_LLADDR(ifp), IEEE80211_ADDR_LEN); | uath_config_multi(sc, CFG_MAC_ADDR, | ||||
vap ? vap->iv_myaddr : ic->ic_macaddr, IEEE80211_ADDR_LEN); | |||||
/* XXX honor net80211 state */ | /* XXX honor net80211 state */ | ||||
uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001); | uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001); | ||||
Context not available. | |||||
UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON, | UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON, | ||||
UATH_FILTER_OP_SET); | UATH_FILTER_OP_SET); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
sc->sc_flags |= UATH_FLAG_INITDONE; | sc->sc_flags |= UATH_FLAG_INITDONE; | ||||
callout_reset(&sc->watchdog_ch, hz, uath_watchdog, sc); | callout_reset(&sc->watchdog_ch, hz, uath_watchdog, sc); | ||||
Context not available. | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
uath_stop_locked(ifp); | uath_stop(sc); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
uath_init(void *arg) | uath_stop(struct uath_softc *sc) | ||||
{ | { | ||||
struct uath_softc *sc = arg; | |||||
UATH_LOCK(sc); | |||||
(void)uath_init_locked(sc); | |||||
UATH_UNLOCK(sc); | |||||
} | |||||
static void | |||||
uath_stop_locked(struct ifnet *ifp) | |||||
{ | |||||
struct uath_softc *sc = ifp->if_softc; | |||||
UATH_ASSERT_LOCKED(sc); | UATH_ASSERT_LOCKED(sc); | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
sc->sc_flags &= ~UATH_FLAG_INITDONE; | sc->sc_flags &= ~UATH_FLAG_INITDONE; | ||||
callout_stop(&sc->stat_ch); | callout_stop(&sc->stat_ch); | ||||
Context not available. | |||||
uath_cmd_write(sc, WDCMSG_TARGET_STOP, NULL, 0, 0); | uath_cmd_write(sc, WDCMSG_TARGET_STOP, NULL, 0, 0); | ||||
} | } | ||||
static void | |||||
uath_stop(struct ifnet *ifp) | |||||
{ | |||||
struct uath_softc *sc = ifp->if_softc; | |||||
UATH_LOCK(sc); | |||||
uath_stop_locked(ifp); | |||||
UATH_UNLOCK(sc); | |||||
} | |||||
static int | static int | ||||
uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val) | uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val) | ||||
{ | { | ||||
Context not available. | |||||
uath_watchdog(void *arg) | uath_watchdog(void *arg) | ||||
{ | { | ||||
struct uath_softc *sc = arg; | struct uath_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
if (sc->sc_tx_timer > 0) { | if (sc->sc_tx_timer > 0) { | ||||
if (--sc->sc_tx_timer == 0) { | if (--sc->sc_tx_timer == 0) { | ||||
device_printf(sc->sc_dev, "device timeout\n"); | device_printf(sc->sc_dev, "device timeout\n"); | ||||
/*uath_init(ifp); XXX needs a process context! */ | /*uath_init(sc); XXX needs a process context! */ | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(ic->ic_oerrors, 1); | ||||
return; | return; | ||||
} | } | ||||
callout_reset(&sc->watchdog_ch, hz, uath_watchdog, sc); | callout_reset(&sc->watchdog_ch, hz, uath_watchdog, sc); | ||||
Context not available. | |||||
UATH_ASSERT_LOCKED(sc); | UATH_ASSERT_LOCKED(sc); | ||||
bf = _uath_getbuf(sc); | bf = _uath_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
DPRINTF(sc, UATH_DEBUG_XMIT, "%s: stop queue\n", __func__); | DPRINTF(sc, UATH_DEBUG_XMIT, "%s: stop queue\n", __func__); | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
} | |||||
return (bf); | return (bf); | ||||
} | } | ||||
Context not available. | |||||
uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c) | uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c) | ||||
{ | { | ||||
#ifdef UATH_DEBUG | #ifdef UATH_DEBUG | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
#endif | #endif | ||||
struct uath_cmd_reset reset; | struct uath_cmd_reset reset; | ||||
Context not available. | |||||
return (error); | return (error); | ||||
} | } | ||||
static int | static void | ||||
uath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | uath_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ieee80211com *ic = ifp->if_l2com; | struct uath_softc *sc = ic->ic_softc; | ||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
struct uath_softc *sc = ifp->if_softc; | |||||
int error; | |||||
int startall = 0; | int startall = 0; | ||||
UATH_LOCK(sc); | UATH_LOCK(sc); | ||||
error = (sc->sc_flags & UATH_FLAG_INVALID) ? ENXIO : 0; | if (sc->sc_flags & UATH_FLAG_INVALID) { | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
if (error) | return; | ||||
return (error); | } | ||||
switch (cmd) { | if (ic->ic_nrunning > 0) { | ||||
case SIOCSIFFLAGS: | if (!(sc->sc_flags & UATH_FLAG_INITDONE)) { | ||||
if (ifp->if_flags & IFF_UP) { | uath_init(sc); | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | startall = 1; | ||||
uath_init(ifp->if_softc); | |||||
startall = 1; | |||||
} | |||||
} else { | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
uath_stop(ifp); | |||||
} | } | ||||
if (startall) | } else if (sc->sc_flags & UATH_FLAG_INITDONE) | ||||
ieee80211_start_all(ic); | uath_stop(sc); | ||||
break; | UATH_UNLOCK(sc); | ||||
case SIOCGIFMEDIA: | if (startall) | ||||
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | ieee80211_start_all(ic); | ||||
break; | |||||
case SIOCGIFADDR: | |||||
error = ether_ioctl(ifp, cmd, data); | |||||
break; | |||||
default: | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
return (error); | |||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
} while ((m = next) != NULL); | } while ((m = next) != NULL); | ||||
} | } | ||||
static int | |||||
uath_transmit(struct ieee80211com *ic, struct mbuf *m) | |||||
{ | |||||
struct uath_softc *sc = ic->ic_softc; | |||||
int error; | |||||
UATH_LOCK(sc); | |||||
if ((sc->sc_flags & UATH_FLAG_INITDONE) == 0) { | |||||
UATH_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
UATH_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
uath_start(sc); | |||||
UATH_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
uath_start(struct ifnet *ifp) | uath_start(struct uath_softc *sc) | ||||
{ | { | ||||
struct uath_data *bf; | struct uath_data *bf; | ||||
struct uath_softc *sc = ifp->if_softc; | |||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m, *next; | struct mbuf *m, *next; | ||||
uath_datahead frags; | uath_datahead frags; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | UATH_ASSERT_LOCKED(sc); | ||||
if ((sc->sc_flags & UATH_FLAG_INITDONE) == 0 || | |||||
(sc->sc_flags & UATH_FLAG_INVALID)) | (sc->sc_flags & UATH_FLAG_INVALID)) | ||||
return; | return; | ||||
UATH_LOCK(sc); | while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
for (;;) { | |||||
bf = uath_getbuf(sc); | bf = uath_getbuf(sc); | ||||
if (bf == NULL) | if (bf == NULL) { | ||||
mbufq_prepend(&sc->sc_snd, m); | |||||
break; | break; | ||||
} | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | |||||
if (m == NULL) { | |||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | |||||
UATH_STAT_INC(sc, st_tx_inactive); | |||||
break; | |||||
} | |||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ||||
m->m_pkthdr.rcvif = NULL; | m->m_pkthdr.rcvif = NULL; | ||||
Context not available. | |||||
next = m->m_nextpkt; | next = m->m_nextpkt; | ||||
if (uath_tx_start(sc, m, ni, bf) != 0) { | if (uath_tx_start(sc, m, ni, bf) != 0) { | ||||
bad: | bad: | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ni->ni_vap->iv_ifp, | ||||
IFCOUNTER_OERRORS, 1); | |||||
reclaim: | reclaim: | ||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | ||||
UATH_STAT_INC(sc, st_tx_inactive); | UATH_STAT_INC(sc, st_tx_inactive); | ||||
Context not available. | |||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} | } | ||||
UATH_UNLOCK(sc); | |||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
const struct ieee80211_bpf_params *params) | const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | |||||
struct uath_data *bf; | struct uath_data *bf; | ||||
struct uath_softc *sc = ifp->if_softc; | struct uath_softc *sc = ic->ic_softc; | ||||
UATH_LOCK(sc); | |||||
/* prevent management frames from being sent if we're not ready */ | /* prevent management frames from being sent if we're not ready */ | ||||
if ((sc->sc_flags & UATH_FLAG_INVALID) || | if ((sc->sc_flags & UATH_FLAG_INVALID) || | ||||
!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | !(sc->sc_flags & UATH_FLAG_INITDONE)) { | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
UATH_UNLOCK(sc); | |||||
return (ENETDOWN); | return (ENETDOWN); | ||||
} | } | ||||
UATH_LOCK(sc); | |||||
/* grab a TX buffer */ | /* grab a TX buffer */ | ||||
bf = uath_getbuf(sc); | bf = uath_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) { | ||||
Context not available. | |||||
sc->sc_seqnum = 0; | sc->sc_seqnum = 0; | ||||
if (uath_tx_start(sc, m, ni, bf) != 0) { | if (uath_tx_start(sc, m, ni, bf) != 0) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | ||||
UATH_STAT_INC(sc, st_tx_inactive); | UATH_STAT_INC(sc, st_tx_inactive); | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
Context not available. | |||||
static void | static void | ||||
uath_set_channel(struct ieee80211com *ic) | uath_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct uath_softc *sc = ic->ic_softc; | ||||
struct uath_softc *sc = ifp->if_softc; | |||||
UATH_LOCK(sc); | UATH_LOCK(sc); | ||||
if ((sc->sc_flags & UATH_FLAG_INVALID) || | if ((sc->sc_flags & UATH_FLAG_INVALID) || | ||||
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | (sc->sc_flags & UATH_FLAG_INITDONE) == 0) { | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
Context not available. | |||||
UATH_LOCK(sc); | UATH_LOCK(sc); | ||||
if ((sc->sc_flags & UATH_FLAG_INVALID) || | if ((sc->sc_flags & UATH_FLAG_INVALID) || | ||||
(ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | (sc->sc_flags & UATH_FLAG_INITDONE) == 0) { | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
Context not available. | |||||
UATH_LOCK(sc); | UATH_LOCK(sc); | ||||
if ((sc->sc_flags & UATH_FLAG_INVALID) || | if ((sc->sc_flags & UATH_FLAG_INVALID) || | ||||
(ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | (sc->sc_flags & UATH_FLAG_INITDONE) == 0) { | ||||
UATH_UNLOCK(sc); | UATH_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
Context not available. | |||||
uath_create_connection(struct uath_softc *sc, uint32_t connid) | uath_create_connection(struct uath_softc *sc, uint32_t connid) | ||||
{ | { | ||||
const struct ieee80211_rateset *rs; | const struct ieee80211_rateset *rs; | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct uath_cmd_create_connection create; | struct uath_cmd_create_connection create; | ||||
Context not available. | |||||
static int | static int | ||||
uath_write_associd(struct uath_softc *sc) | uath_write_associd(struct uath_softc *sc) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct uath_cmd_set_associd associd; | struct uath_cmd_set_associd associd; | ||||
Context not available. | |||||
int error; | int error; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct uath_softc *sc = ic->ic_ifp->if_softc; | struct uath_softc *sc = ic->ic_softc; | ||||
struct uath_vap *uvp = UATH_VAP(vap); | struct uath_vap *uvp = UATH_VAP(vap); | ||||
DPRINTF(sc, UATH_DEBUG_STATE, | DPRINTF(sc, UATH_DEBUG_STATE, | ||||
Context not available. | |||||
struct uath_rx_desc **pdesc) | struct uath_rx_desc **pdesc) | ||||
{ | { | ||||
struct uath_softc *sc = usbd_xfer_softc(xfer); | struct uath_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct uath_chunk *chunk; | struct uath_chunk *chunk; | ||||
struct uath_rx_desc *desc; | struct uath_rx_desc *desc; | ||||
struct mbuf *m = data->m, *mnew, *mp; | struct mbuf *m = data->m, *mnew, *mp; | ||||
Context not available. | |||||
if (actlen < (int)UATH_MIN_RXBUFSZ) { | if (actlen < (int)UATH_MIN_RXBUFSZ) { | ||||
DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | ||||
"%s: wrong xfer size (len=%d)\n", __func__, actlen); | "%s: wrong xfer size (len=%d)\n", __func__, actlen); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
Context not available. | |||||
chunk = (struct uath_chunk *)data->buf; | chunk = (struct uath_chunk *)data->buf; | ||||
if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) { | if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) { | ||||
device_printf(sc->sc_dev, "%s: strange response\n", __func__); | device_printf(sc->sc_dev, "%s: strange response\n", __func__); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
Context not available. | |||||
if ((sc->sc_intrx_len + sizeof(struct uath_rx_desc) + | if ((sc->sc_intrx_len + sizeof(struct uath_rx_desc) + | ||||
chunklen) > UATH_MAX_INTRX_SIZE) { | chunklen) > UATH_MAX_INTRX_SIZE) { | ||||
UATH_STAT_INC(sc, st_invalidlen); | UATH_STAT_INC(sc, st_invalidlen); | ||||
if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
if (sc->sc_intrx_head != NULL) | if (sc->sc_intrx_head != NULL) | ||||
m_freem(sc->sc_intrx_head); | m_freem(sc->sc_intrx_head); | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
Context not available. | |||||
if (mnew == NULL) { | if (mnew == NULL) { | ||||
DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | ||||
"%s: can't get new mbuf, drop frame\n", __func__); | "%s: can't get new mbuf, drop frame\n", __func__); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
if (sc->sc_intrx_head != NULL) | if (sc->sc_intrx_head != NULL) | ||||
m_freem(sc->sc_intrx_head); | m_freem(sc->sc_intrx_head); | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
Context not available. | |||||
DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | ||||
"%s: bad descriptor (len=%d)\n", __func__, | "%s: bad descriptor (len=%d)\n", __func__, | ||||
be32toh(desc->len)); | be32toh(desc->len)); | ||||
if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
UATH_STAT_INC(sc, st_toobigrxpkt); | UATH_STAT_INC(sc, st_toobigrxpkt); | ||||
if (sc->sc_intrx_head != NULL) | if (sc->sc_intrx_head != NULL) | ||||
m_freem(sc->sc_intrx_head); | m_freem(sc->sc_intrx_head); | ||||
Context not available. | |||||
/* finalize mbuf */ | /* finalize mbuf */ | ||||
if (sc->sc_intrx_head == NULL) { | if (sc->sc_intrx_head == NULL) { | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_pkthdr.len = m->m_len = | m->m_pkthdr.len = m->m_len = | ||||
be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; | be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; | ||||
m->m_data += sizeof(struct uath_chunk); | m->m_data += sizeof(struct uath_chunk); | ||||
} else { | } else { | ||||
mp = sc->sc_intrx_head; | mp = sc->sc_intrx_head; | ||||
mp->m_pkthdr.rcvif = ifp; | |||||
mp->m_flags |= M_PKTHDR; | mp->m_flags |= M_PKTHDR; | ||||
mp->m_pkthdr.len = sc->sc_intrx_len; | mp->m_pkthdr.len = sc->sc_intrx_len; | ||||
m = mp; | m = mp; | ||||
Context not available. | |||||
tap->wr_antnoise = -95; | tap->wr_antnoise = -95; | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | |||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
return (m); | return (m); | ||||
Context not available. | |||||
uath_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | uath_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct uath_softc *sc = usbd_xfer_softc(xfer); | struct uath_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m = NULL; | struct mbuf *m = NULL; | ||||
Context not available. | |||||
m = NULL; | m = NULL; | ||||
desc = NULL; | desc = NULL; | ||||
} | } | ||||
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && | |||||
!IFQ_IS_EMPTY(&ifp->if_snd)) | |||||
uath_start(ifp); | |||||
UATH_LOCK(sc); | UATH_LOCK(sc); | ||||
uath_start(sc); | |||||
break; | break; | ||||
default: | default: | ||||
/* needs it to the inactive queue due to a error. */ | /* needs it to the inactive queue due to a error. */ | ||||
Context not available. | |||||
} | } | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
usbd_xfer_set_stall(xfer); | usbd_xfer_set_stall(xfer); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto setup; | goto setup; | ||||
} | } | ||||
break; | break; | ||||
Context not available. | |||||
uath_data_txeof(struct usb_xfer *xfer, struct uath_data *data) | uath_data_txeof(struct usb_xfer *xfer, struct uath_data *data) | ||||
{ | { | ||||
struct uath_softc *sc = usbd_xfer_softc(xfer); | struct uath_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct mbuf *m; | |||||
UATH_ASSERT_LOCKED(sc); | UATH_ASSERT_LOCKED(sc); | ||||
/* | |||||
* Do any tx complete callback. Note this must be done before releasing | |||||
* the node reference. | |||||
*/ | |||||
if (data->m) { | if (data->m) { | ||||
m = data->m; | /* XXX status? */ | ||||
if (m->m_flags & M_TXCB && | ieee80211_tx_complete(data->ni, data->m, 0); | ||||
(sc->sc_flags & UATH_FLAG_INVALID) == 0) { | |||||
/* XXX status? */ | |||||
ieee80211_process_callback(data->ni, m, 0); | |||||
} | |||||
m_freem(m); | |||||
data->m = NULL; | data->m = NULL; | ||||
} | |||||
if (data->ni) { | |||||
if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) | |||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | data->ni = NULL; | ||||
} | } | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
uath_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) | uath_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct uath_softc *sc = usbd_xfer_softc(xfer); | struct uath_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct uath_data *data; | struct uath_data *data; | ||||
UATH_ASSERT_LOCKED(sc); | UATH_ASSERT_LOCKED(sc); | ||||
Context not available. | |||||
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); | usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); | ||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
UATH_UNLOCK(sc); | uath_start(sc); | ||||
uath_start(ifp); | |||||
UATH_LOCK(sc); | |||||
break; | break; | ||||
default: | default: | ||||
data = STAILQ_FIRST(&sc->sc_tx_active); | data = STAILQ_FIRST(&sc->sc_tx_active); | ||||
Context not available. | |||||
if (data == NULL) | if (data == NULL) | ||||
goto setup; | goto setup; | ||||
if (data->ni != NULL) { | if (data->ni != NULL) { | ||||
if_inc_counter(data->ni->ni_vap->iv_ifp, | |||||
IFCOUNTER_OERRORS, 1); | |||||
if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) | if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) | ||||
ieee80211_free_node(data->ni); | ieee80211_free_node(data->ni); | ||||
data->ni = NULL; | data->ni = NULL; | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
} | } | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
usbd_xfer_set_stall(xfer); | usbd_xfer_set_stall(xfer); | ||||
Context not available. |