diff options
Diffstat (limited to 'sys')
78 files changed, 6107 insertions, 3922 deletions
diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c index 815c68b..3606e14 100644 --- a/sys/dev/ath/ath_rate/sample/sample.c +++ b/sys/dev/ath/ath_rate/sample/sample.c @@ -488,7 +488,8 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, #define RATE(ix) (DOT11RATE(ix) / 2) struct sample_node *sn = ATH_NODE_SAMPLE(an); struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const HAL_RATE_TABLE *rt = sc->sc_currates; const int size_bin = size_to_bin(frameLen); int rix, mrr, best_rix, change_rates; @@ -855,7 +856,8 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, const struct ath_rc_series *rc, const struct ath_tx_status *ts, int frame_size, int nframes, int nbad) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct sample_node *sn = ATH_NODE_SAMPLE(an); int final_rix, short_tries, long_tries; const HAL_RATE_TABLE *rt = sc->sc_currates; @@ -1301,7 +1303,8 @@ static int ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) { struct ath_softc *sc = arg1; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int error, v; v = 0; diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h index 5495141..1c57dee 100644 --- a/sys/dev/ath/ath_rate/sample/sample.h +++ b/sys/dev/ath/ath_rate/sample/sample.h @@ -134,7 +134,8 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, int long_retries, int is_ht40) { const HAL_RATE_TABLE *rt = sc->sc_currates; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int rts, cts; unsigned t_slot = 20; diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index f40f4fa..2c935a2b 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -151,15 +151,15 @@ static struct ieee80211vap *ath_vap_create(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void ath_vap_delete(struct ieee80211vap *); -static void ath_init(struct ath_softc *); -static void ath_stop_locked(struct ath_softc *); -static void ath_stop(struct ath_softc *); +static void ath_init(void *); +static void ath_stop_locked(struct ifnet *); +static void ath_stop(struct ifnet *); static int ath_reset_vap(struct ieee80211vap *, u_long); -static int ath_transmit(struct ieee80211com *, struct mbuf *); +static int ath_transmit(struct ifnet *ifp, struct mbuf *m); +static void ath_qflush(struct ifnet *ifp); static int ath_media_change(struct ifnet *); static void ath_watchdog(void *); -static int ath_ioctl(struct ieee80211com *, u_long, void *); -static void ath_parent(struct ieee80211com *); +static int ath_ioctl(struct ifnet *, u_long, caddr_t); static void ath_fatal_proc(void *, int); static void ath_bmiss_vap(struct ieee80211vap *); static void ath_bmiss_proc(void *, int); @@ -571,19 +571,34 @@ ath_fetch_mac_kenv(struct ath_softc *sc, uint8_t *macaddr) int ath_attach(u_int16_t devid, struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; struct ath_hal *ah = NULL; HAL_STATUS status; int error = 0, i; u_int wmodes; + uint8_t macaddr[IEEE80211_ADDR_LEN]; int rx_chainmask, tx_chainmask; HAL_OPS_CONFIG ah_config; DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); + CURVNET_SET(vnet0); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + error = ENOSPC; + CURVNET_RESTORE(); + goto bad; + } + ic = ifp->if_l2com; ic->ic_softc = sc; ic->ic_name = device_get_nameunit(sc->sc_dev); + if_initname(ifp, device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev)); + CURVNET_RESTORE(); + /* * Configure the initial configuration data. * @@ -717,8 +732,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_tq = taskqueue_create("ath_taskq", M_NOWAIT, taskqueue_thread_enqueue, &sc->sc_tq); - taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(sc->sc_dev)); + taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, + "%s taskq", ifp->if_xname); TASK_INIT(&sc->sc_rxtask, 0, sc->sc_rx.recv_tasklet, sc); TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc); @@ -861,6 +876,17 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) ath_led_config(sc); ath_hal_setledstate(ah, HAL_LED_INIT); + ifp->if_softc = sc; + ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_transmit = ath_transmit; + ifp->if_qflush = ath_qflush; + ifp->if_ioctl = ath_ioctl; + ifp->if_init = ath_init; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + ic->ic_ifp = ifp; /* XXX not right but it's not used anywhere important */ ic->ic_phytype = IEEE80211_T_OFDM; ic->ic_opmode = IEEE80211_M_STA; @@ -1182,11 +1208,11 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_hasveol = ath_hal_hasveol(ah); /* get mac address from kenv first, then hardware */ - if (ath_fetch_mac_kenv(sc, ic->ic_macaddr) == 0) { + if (ath_fetch_mac_kenv(sc, macaddr) == 0) { /* Tell the HAL now about the new MAC */ - ath_hal_setmac(ah, ic->ic_macaddr); + ath_hal_setmac(ah, macaddr); } else { - ath_hal_getmac(ah, ic->ic_macaddr); + ath_hal_getmac(ah, macaddr); } if (sc->sc_hasbmask) @@ -1195,15 +1221,12 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) /* NB: used to size node table key mapping array */ ic->ic_max_keyix = sc->sc_keymax; /* call MI attach routine. */ - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_setregdomain = ath_setregdomain; ic->ic_getradiocaps = ath_getradiocaps; sc->sc_opmode = HAL_M_STA; /* override default methods */ - ic->ic_ioctl = ath_ioctl; - ic->ic_parent = ath_parent; - ic->ic_transmit = ath_transmit; ic->ic_newassoc = ath_newassoc; ic->ic_updateslot = ath_updateslot; ic->ic_wme.wme_update = ath_wme_update; @@ -1299,6 +1322,16 @@ bad2: bad: if (ah) ath_hal_detach(ah); + + /* + * To work around scoping issues with CURVNET_SET/CURVNET_RESTORE.. + */ + if (ifp != NULL && ifp->if_vnet) { + CURVNET_SET(ifp->if_vnet); + if_free(ifp); + CURVNET_RESTORE(); + } else if (ifp != NULL) + if_free(ifp); sc->sc_invalid = 1; return error; } @@ -1306,6 +1339,10 @@ bad: int ath_detach(struct ath_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; + + DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); /* * NB: the order of these is important: @@ -1330,14 +1367,14 @@ ath_detach(struct ath_softc *sc) ATH_LOCK(sc); ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); /* * Stop things cleanly. */ - ath_stop_locked(sc); - ATH_UNLOCK(sc); + ath_stop(ifp); - ieee80211_ifdetach(&sc->sc_ic); + ieee80211_ifdetach(ifp->if_l2com); taskqueue_free(sc->sc_tq); #ifdef ATH_TX99_DIAG if (sc->sc_tx99 != NULL) @@ -1357,6 +1394,10 @@ ath_detach(struct ath_softc *sc) ath_tx_cleanup(sc); ath_hal_detach(sc->sc_ah); /* NB: sets chip in full sleep */ + CURVNET_SET(ifp->if_vnet); + if_free(ifp); + CURVNET_RESTORE(); + return 0; } @@ -1432,7 +1473,7 @@ ath_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac0[IEEE80211_ADDR_LEN]) { - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_vap *avp; struct ieee80211vap *vap; uint8_t mac[IEEE80211_ADDR_LEN]; @@ -1540,7 +1581,8 @@ ath_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, vap = &avp->av_vap; /* XXX can't hold mutex across if_alloc */ ATH_UNLOCK(sc); - error = ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + error = ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, + bssid, mac); ATH_LOCK(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: error %d creating vap\n", @@ -1674,8 +1716,7 @@ ath_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ATH_UNLOCK(sc); /* complete setup */ - ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status, - mac); + ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status); return vap; bad2: reclaim_address(sc, mac); @@ -1690,7 +1731,8 @@ static void ath_vap_delete(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp = ATH_VAP(vap); @@ -1699,7 +1741,7 @@ ath_vap_delete(struct ieee80211vap *vap) ATH_UNLOCK(sc); DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); - if (sc->sc_running) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* * Quiesce the hardware while we remove the vap. In * particular we need to reclaim all references to @@ -1782,7 +1824,7 @@ ath_vap_delete(struct ieee80211vap *vap) #endif free(avp, M_80211_VAP); - if (sc->sc_running) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* * Restart rx+tx machines if still running (RUNNING will * be reset if we just destroyed the last vap). @@ -1809,9 +1851,13 @@ ath_vap_delete(struct ieee80211vap *vap) void ath_suspend(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - sc->sc_resume_up = ic->ic_nrunning != 0; + DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); + + sc->sc_resume_up = (ifp->if_flags & IFF_UP) != 0; ieee80211_suspend_all(ic); /* @@ -1852,7 +1898,8 @@ ath_suspend(struct ath_softc *sc) static void ath_reset_keycache(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; int i; @@ -1894,7 +1941,8 @@ ath_update_chainmasks(struct ath_softc *sc, struct ieee80211_channel *chan) void ath_resume(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; @@ -1967,8 +2015,12 @@ ath_resume(struct ath_softc *sc) void ath_shutdown(struct ath_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; - ath_stop(sc); + DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); + + ath_stop(ifp); /* NB: no point powering down chip as we're about to reboot */ } @@ -1979,6 +2031,7 @@ void ath_intr(void *arg) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; HAL_INT status = 0; uint32_t txqs; @@ -2017,11 +2070,12 @@ ath_intr(void *arg) ath_power_set_power_state(sc, HAL_PM_AWAKE); ATH_UNLOCK(sc); - if (sc->sc_ic.ic_nrunning == 0 && sc->sc_running == 0) { + if ((ifp->if_flags & IFF_UP) == 0 || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { HAL_INT status; - DPRINTF(sc, ATH_DEBUG_ANY, "%s: ic_nrunning %d sc_running %d\n", - __func__, sc->sc_ic.ic_nrunning, sc->sc_running); + DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", + __func__, ifp->if_flags); ath_hal_getisr(ah, &status); /* clear ISR */ ath_hal_intrset(ah, 0); /* disable further intr's */ ATH_PCU_UNLOCK(sc); @@ -2259,6 +2313,7 @@ static void ath_fatal_proc(void *arg, int pending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; u_int32_t *state; u_int32_t len; void *sp; @@ -2279,13 +2334,13 @@ ath_fatal_proc(void *arg, int pending) "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", state[0], state[1] , state[2], state[3], state[4], state[5]); } - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(ifp, ATH_RESET_NOLOSS); } static void ath_bmiss_vap(struct ieee80211vap *vap) { - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; /* * Workaround phantom bmiss interrupts by sanity-checking @@ -2306,6 +2361,8 @@ ath_bmiss_vap(struct ieee80211vap *vap) ATH_UNLOCK(sc); if ((vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) == 0) { + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; u_int64_t lastrx = sc->sc_lastrx; u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); /* XXX should take a locked ref to iv_bss */ @@ -2363,6 +2420,7 @@ static void ath_bmiss_proc(void *arg, int pending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t hangs; DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); @@ -2380,12 +2438,12 @@ ath_bmiss_proc(void *arg, int pending) * to clear. */ if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) { - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(ifp, ATH_RESET_NOLOSS); device_printf(sc->sc_dev, "bb hang detected (0x%x), resetting\n", hangs); } else { - ath_reset(sc, ATH_RESET_NOLOSS); - ieee80211_beacon_miss(&sc->sc_ic); + ath_reset(ifp, ATH_RESET_NOLOSS); + ieee80211_beacon_miss(ifp->if_l2com); } /* Force a beacon resync, in case they've drifted */ @@ -2405,7 +2463,8 @@ ath_bmiss_proc(void *arg, int pending) static void ath_settkipmic(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; if ((ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIP) && !sc->sc_wmetkipmic) { if (ic->ic_flags & IEEE80211_F_WME) { @@ -2419,9 +2478,11 @@ ath_settkipmic(struct ath_softc *sc) } static void -ath_init(struct ath_softc *sc) +ath_init(void *arg) { - struct ieee80211com *ic = &sc->sc_ic; + struct ath_softc *sc = (struct ath_softc *) arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; @@ -2440,7 +2501,7 @@ ath_init(struct ath_softc *sc) * Stop anything previously setup. This is safe * whether this is the first time through or not. */ - ath_stop_locked(sc); + ath_stop_locked(ifp); /* * The basic interface to setting the hardware in a good @@ -2566,7 +2627,7 @@ ath_init(struct ath_softc *sc) DPRINTF(sc, ATH_DEBUG_RESET, "%s: imask=0x%x\n", __func__, sc->sc_imask); - sc->sc_running = 1; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->sc_wd_ch, hz, ath_watchdog, sc); ath_hal_intrset(ah, sc->sc_imask); @@ -2582,10 +2643,14 @@ ath_init(struct ath_softc *sc) } static void -ath_stop_locked(struct ath_softc *sc) +ath_stop_locked(struct ifnet *ifp) { + struct ath_softc *sc = ifp->if_softc; struct ath_hal *ah = sc->sc_ah; + DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", + __func__, sc->sc_invalid, ifp->if_flags); + ATH_LOCK_ASSERT(sc); /* @@ -2593,7 +2658,7 @@ ath_stop_locked(struct ath_softc *sc) */ ath_power_set_power_state(sc, HAL_PM_AWAKE); - if (sc->sc_running) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* * Shutdown the hardware and driver: * reset 802.11 state machine @@ -2615,7 +2680,7 @@ ath_stop_locked(struct ath_softc *sc) #endif callout_stop(&sc->sc_wd_ch); sc->sc_wd_timer = 0; - sc->sc_running = 0; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; if (!sc->sc_invalid) { if (sc->sc_softled) { callout_stop(&sc->sc_ledtimer); @@ -2767,11 +2832,12 @@ ath_reset_grablock(struct ath_softc *sc, int dowait) */ static void -ath_stop(struct ath_softc *sc) +ath_stop(struct ifnet *ifp) { - + struct ath_softc *sc = ifp->if_softc; + ATH_LOCK(sc); - ath_stop_locked(sc); + ath_stop_locked(ifp); ATH_UNLOCK(sc); } @@ -2783,9 +2849,10 @@ ath_stop(struct ath_softc *sc) * to reset or reload hardware state. */ int -ath_reset(struct ath_softc *sc, ATH_RESET_TYPE reset_type) +ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) { - struct ieee80211com *ic = &sc->sc_ic; + struct ath_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; int i; @@ -2947,6 +3014,15 @@ ath_reset(struct ath_softc *sc, ATH_RESET_TYPE reset_type) } } + /* + * This may have been set during an ath_start() call which + * set this once it detected a concurrent TX was going on. + * So, clear it. + */ + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); + ATH_LOCK(sc); ath_power_restore_power_state(sc); ATH_UNLOCK(sc); @@ -2968,7 +3044,8 @@ static int ath_reset_vap(struct ieee80211vap *vap, u_long cmd) { struct ieee80211com *ic = vap->iv_ic; - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; struct ath_hal *ah = sc->sc_ah; switch (cmd) { @@ -2983,7 +3060,7 @@ ath_reset_vap(struct ieee80211vap *vap, u_long cmd) return 0; } /* XXX? Full or NOLOSS? */ - return ath_reset(sc, ATH_RESET_FULL); + return ath_reset(ifp, ATH_RESET_FULL); } struct ath_buf * @@ -3143,12 +3220,24 @@ ath_getbuf(struct ath_softc *sc, ath_buf_type_t btype) bf = _ath_getbuf_locked(sc, ATH_BUFTYPE_NORMAL); ATH_TXBUF_UNLOCK(sc); if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: stop queue\n", __func__); sc->sc_stats.ast_tx_qstop++; + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); } return bf; } +static void +ath_qflush(struct ifnet *ifp) +{ + + /* XXX TODO */ +} + /* * Transmit a single frame. * @@ -3156,9 +3245,10 @@ ath_getbuf(struct ath_softc *sc, ath_buf_type_t btype) * fails, so don't free the node reference here. */ static int -ath_transmit(struct ieee80211com *ic, struct mbuf *m) +ath_transmit(struct ifnet *ifp, struct mbuf *m) { - struct ath_softc *sc = ic->ic_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; struct mbuf *next; struct ath_buf *bf; @@ -3173,7 +3263,10 @@ ath_transmit(struct ieee80211com *ic, struct mbuf *m) DPRINTF(sc, ATH_DEBUG_XMIT, "%s: sc_inreset_cnt > 0; bailing\n", __func__); ATH_PCU_UNLOCK(sc); + IF_LOCK(&ifp->if_snd); sc->sc_stats.ast_tx_qstop++; + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); ATH_KTR(sc, ATH_KTR_TX, 0, "ath_start_task: OACTIVE, finish"); return (ENOBUFS); /* XXX should be EINVAL or? */ } @@ -3213,6 +3306,8 @@ ath_transmit(struct ieee80211com *ic, struct mbuf *m) if ((!(m->m_flags & M_EAPOL)) && (ATH_NODE(ni)->an_swq_depth > sc->sc_txq_node_maxdepth)) { sc->sc_stats.ast_tx_nodeq_overflow++; + m_freem(m); + m = NULL; retval = ENOBUFS; goto finish; } @@ -3236,6 +3331,8 @@ ath_transmit(struct ieee80211com *ic, struct mbuf *m) if ((!(m->m_flags & M_EAPOL)) && (sc->sc_txbuf_cnt <= sc->sc_txq_data_minfree)) { sc->sc_stats.ast_tx_nobuf++; + m_freem(m); + m = NULL; retval = ENOBUFS; goto finish; } @@ -3263,6 +3360,11 @@ ath_transmit(struct ieee80211com *ic, struct mbuf *m) * above. */ sc->sc_stats.ast_tx_nobuf++; + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); + m_freem(m); + m = NULL; retval = ENOBUFS; goto finish; } @@ -3284,13 +3386,8 @@ ath_transmit(struct ieee80211com *ic, struct mbuf *m) DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of txfrag buffers\n", __func__); sc->sc_stats.ast_tx_nofrag++; - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); - /* - * XXXGL: is mbuf valid after ath_txfrag_setup? If yes, - * we shouldn't free it but return back. - */ + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ath_freetx(m); - m = NULL; goto bad; } @@ -3332,6 +3429,12 @@ ath_transmit(struct ieee80211com *ic, struct mbuf *m) } } + /* + * Bump the ifp output counter. + * + * XXX should use atomics? + */ + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); nextfrag: /* * Pass the frame to the h/w for transmission. @@ -3351,7 +3454,7 @@ nextfrag: next = m->m_nextpkt; if (ath_tx_start(sc, ni, bf, m)) { bad: - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); reclaim: bf->bf_m = NULL; bf->bf_node = NULL; @@ -3435,7 +3538,8 @@ ath_media_change(struct ifnet *ifp) static void ath_key_update_begin(struct ieee80211vap *vap) { - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); taskqueue_block(sc->sc_tq); @@ -3444,7 +3548,8 @@ ath_key_update_begin(struct ieee80211vap *vap) static void ath_key_update_end(struct ieee80211vap *vap) { - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); taskqueue_unblock(sc->sc_tq); @@ -3475,41 +3580,32 @@ ath_update_promisc(struct ieee80211com *ic) static void ath_update_mcast_hw(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; u_int32_t mfilt[2]; /* calculate and install multicast filter */ - if (ic->ic_allmulti == 0) { - struct ieee80211vap *vap; - struct ifnet *ifp; + if ((ifp->if_flags & IFF_ALLMULTI) == 0) { struct ifmultiaddr *ifma; - /* * Merge multicast addresses to form the hardware filter. */ mfilt[0] = mfilt[1] = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - uint32_t val; - uint8_t pos; - - /* calculate XOR of eight 6bit values */ - dl = LLADDR((struct sockaddr_dl *) - ifma->ifma_addr); - val = LE_READ_4(dl + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ - val; - val = LE_READ_4(dl + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ - val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); - } - if_maddr_runlock(ifp); + if_maddr_rlock(ifp); /* XXX need some fiddling to remove? */ + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + caddr_t dl; + u_int32_t val; + u_int8_t pos; + + /* calculate XOR of eight 6bit values */ + dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); + val = LE_READ_4(dl + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = LE_READ_4(dl + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); } + if_maddr_runlock(ifp); } else mfilt[0] = mfilt[1] = ~0; @@ -3542,7 +3638,7 @@ ath_update_mcast(struct ieee80211com *ic) void ath_mode_init(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; u_int32_t rfilt; @@ -3553,8 +3649,15 @@ ath_mode_init(struct ath_softc *sc) /* configure operational mode */ ath_hal_setopmode(ah); + DPRINTF(sc, ATH_DEBUG_STATE | ATH_DEBUG_MODE, + "%s: ah=%p, ifp=%p, if_addr=%p\n", + __func__, + ah, + ifp, + (ifp == NULL) ? NULL : ifp->if_addr); + /* handle any link-level address change */ - ath_hal_setmac(ah, ic->ic_macaddr); + ath_hal_setmac(ah, IF_LLADDR(ifp)); /* calculate and install multicast filter */ ath_update_mcast_hw(sc); @@ -3566,7 +3669,7 @@ ath_mode_init(struct ath_softc *sc) void ath_setslottime(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; u_int usec; @@ -3650,11 +3753,12 @@ static void ath_reset_proc(void *arg, int pending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; #if 0 device_printf(sc->sc_dev, "%s: resetting\n", __func__); #endif - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(ifp, ATH_RESET_NOLOSS); } /* @@ -3664,6 +3768,7 @@ static void ath_bstuck_proc(void *arg, int pending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t hangs = 0; if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) @@ -3681,7 +3786,7 @@ ath_bstuck_proc(void *arg, int pending) * This assumes that there's no simultaneous channel mode change * occuring. */ - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(ifp, ATH_RESET_NOLOSS); } static void @@ -4051,7 +4156,7 @@ static struct ieee80211_node * ath_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic = vap->iv_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space; struct ath_node *an; @@ -4078,7 +4183,7 @@ static void ath_node_cleanup(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: an %p\n", __func__, ni->ni_macaddr, ":", ATH_NODE(ni)); @@ -4093,7 +4198,7 @@ static void ath_node_free(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: an %p\n", __func__, ni->ni_macaddr, ":", ATH_NODE(ni)); @@ -4105,7 +4210,7 @@ static void ath_node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise) { struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; *rssi = ic->ic_node_getrssi(ni); @@ -4243,7 +4348,8 @@ ath_txq_update(struct ath_softc *sc, int ac) { #define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1) #define ATH_TXOP_TO_US(v) (v<<5) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_txq *txq = sc->sc_ac2q[ac]; struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; struct ath_hal *ah = sc->sc_ah; @@ -4316,7 +4422,7 @@ ath_txq_update(struct ath_softc *sc, int ac) int ath_wme_update(struct ieee80211com *ic) { - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; return !ath_txq_update(sc, WME_AC_BE) || !ath_txq_update(sc, WME_AC_BK) || @@ -4367,7 +4473,8 @@ ath_tx_update_stats(struct ath_softc *sc, struct ath_tx_status *ts, struct ath_buf *bf) { struct ieee80211_node *ni = bf->bf_node; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int sr, lr, pri; if (ts->ts_status == 0) { @@ -4722,6 +4829,7 @@ static void ath_tx_proc_q0(void *arg, int npending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t txqs; ATH_PCU_LOCK(sc); @@ -4742,6 +4850,9 @@ ath_tx_proc_q0(void *arg, int npending) sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); if (TXQACTIVE(txqs, sc->sc_cabq->axq_qnum)) ath_tx_processq(sc, sc->sc_cabq, 1); + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); sc->sc_wd_timer = 0; if (sc->sc_softled) @@ -4766,6 +4877,7 @@ static void ath_tx_proc_q0123(void *arg, int npending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; int nacked; uint32_t txqs; @@ -4799,6 +4911,9 @@ ath_tx_proc_q0123(void *arg, int npending) if (nacked) sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); sc->sc_wd_timer = 0; if (sc->sc_softled) @@ -4822,6 +4937,7 @@ static void ath_tx_proc(void *arg, int npending) { struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; int i, nacked; uint32_t txqs; @@ -4847,6 +4963,10 @@ ath_tx_proc(void *arg, int npending) if (nacked) sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); + /* XXX check this inside of IF_LOCK? */ + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); sc->sc_wd_timer = 0; if (sc->sc_softled) @@ -5157,7 +5277,7 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_aggr_depth--; #ifdef ATH_DEBUG if (sc->sc_debug & ATH_DEBUG_RESET) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; int status = 0; /* @@ -5302,8 +5422,9 @@ void ath_legacy_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) { struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf_last; + struct ifnet *ifp = sc->sc_ifp; int i; + struct ath_buf *bf_last; (void) ath_stoptxdma(sc); @@ -5355,12 +5476,15 @@ ath_legacy_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) ath_printtxbuf(sc, bf, sc->sc_bhalq, 0, ath_hal_txprocdesc(ah, bf->bf_lastds, &bf->bf_status.ds_txstat) == HAL_OK); - ieee80211_dump_pkt(&sc->sc_ic, + ieee80211_dump_pkt(ifp->if_l2com, mtod(bf->bf_m, const uint8_t *), bf->bf_m->m_len, 0, -1); } } #endif /* ATH_DEBUG */ + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); sc->sc_wd_timer = 0; } @@ -5391,7 +5515,8 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan) static int ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; int ret = 0; @@ -5526,6 +5651,9 @@ finish: ath_hal_intrset(ah, sc->sc_imask); ATH_PCU_UNLOCK(sc); + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); ath_txrx_start(sc); /* XXX ath_start? */ @@ -5541,7 +5669,8 @@ ath_calibrate(void *arg) { struct ath_softc *sc = arg; struct ath_hal *ah = sc->sc_ah; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; HAL_BOOL longCal, isCalDone = AH_TRUE; HAL_BOOL aniCal, shortCal = AH_FALSE; int nextcal; @@ -5667,12 +5796,12 @@ restart: static void ath_scan_start(struct ieee80211com *ic) { - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; struct ath_hal *ah = sc->sc_ah; u_int32_t rfilt; /* XXX calibration timer? */ - /* XXXGL: is constant ieee80211broadcastaddr a correct choice? */ ATH_LOCK(sc); sc->sc_scanning = 1; @@ -5682,17 +5811,18 @@ ath_scan_start(struct ieee80211com *ic) ATH_PCU_LOCK(sc); ath_hal_setrxfilter(ah, rfilt); - ath_hal_setassocid(ah, ieee80211broadcastaddr, 0); + ath_hal_setassocid(ah, ifp->if_broadcastaddr, 0); ATH_PCU_UNLOCK(sc); DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0\n", - __func__, rfilt, ether_sprintf(ieee80211broadcastaddr)); + __func__, rfilt, ether_sprintf(ifp->if_broadcastaddr)); } static void ath_scan_end(struct ieee80211com *ic) { - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; struct ath_hal *ah = sc->sc_ah; u_int32_t rfilt; @@ -5732,7 +5862,8 @@ ath_scan_end(struct ieee80211com *ic) static void ath_update_chw(struct ieee80211com *ic) { - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_STATE, "%s: called\n", __func__); ath_set_channel(ic); @@ -5742,7 +5873,8 @@ ath_update_chw(struct ieee80211com *ic) static void ath_set_channel(struct ieee80211com *ic) { - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; ATH_LOCK(sc); ath_power_set_power_state(sc, HAL_PM_AWAKE); @@ -5784,7 +5916,7 @@ static int ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_vap *avp = ATH_VAP(vap); struct ath_hal *ah = sc->sc_ah; struct ieee80211_node *ni = NULL; @@ -6120,7 +6252,7 @@ static void ath_setup_stationkey(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; ieee80211_keyix keyix, rxkeyix; /* XXX should take a locked ref to vap->iv_bss */ @@ -6153,7 +6285,7 @@ ath_newassoc(struct ieee80211_node *ni, int isnew) { struct ath_node *an = ATH_NODE(ni); struct ieee80211vap *vap = ni->ni_vap; - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; const struct ieee80211_txparam *tp = ni->ni_txparms; an->an_mcastrix = ath_tx_findrix(sc, tp->mcastrate); @@ -6205,7 +6337,7 @@ static int ath_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *reg, int nchans, struct ieee80211_channel chans[]) { - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; @@ -6229,7 +6361,7 @@ static void ath_getradiocaps(struct ieee80211com *ic, int maxchans, int *nchans, struct ieee80211_channel chans[]) { - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; DPRINTF(sc, ATH_DEBUG_REGDOMAIN, "%s: use rd %u cc %d\n", @@ -6244,7 +6376,8 @@ ath_getradiocaps(struct ieee80211com *ic, static int ath_getchannels(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; @@ -6406,12 +6539,12 @@ static void ath_watchdog(void *arg) { struct ath_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; int do_reset = 0; ATH_LOCK_ASSERT(sc); if (sc->sc_wd_timer != 0 && --sc->sc_wd_timer == 0) { + struct ifnet *ifp = sc->sc_ifp; uint32_t hangs; ath_power_set_power_state(sc, HAL_PM_AWAKE); @@ -6423,7 +6556,7 @@ ath_watchdog(void *arg) } else device_printf(sc->sc_dev, "device timeout\n"); do_reset = 1; - counter_u64_add(ic->ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); sc->sc_stats.ast_watchdog++; ath_power_restore_power_state(sc); @@ -6449,7 +6582,7 @@ static int ath_ioctl_ratestats(struct ath_softc *sc, struct ath_rateioctl *rs) { struct ath_node *an; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211_node *ni; int error = 0; @@ -6555,23 +6688,31 @@ bad: } #endif /* ATH_DIAGAPI */ -static void -ath_parent(struct ieee80211com *ic) +static int +ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct ath_softc *sc = ic->ic_softc; +#define IS_RUNNING(ifp) \ + ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + struct ath_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *)data; + const HAL_RATE_TABLE *rt; + int error = 0; - ATH_LOCK(sc); - if (ic->ic_nrunning > 0) { - /* - * To avoid rescanning another access point, - * do not call ath_init() here. Instead, - * only reflect promisc mode settings. - */ - if (sc->sc_running) { + switch (cmd) { + case SIOCSIFFLAGS: + if (IS_RUNNING(ifp)) { + /* + * To avoid rescanning another access point, + * do not call ath_init() here. Instead, + * only reflect promisc mode settings. + */ + ATH_LOCK(sc); ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_mode_init(sc); ath_power_restore_power_state(sc); - } else if (!sc->sc_invalid) { + ATH_UNLOCK(sc); + } else if (ifp->if_flags & IFF_UP) { /* * Beware of being called during attach/detach * to reset promiscuous mode. In that case we @@ -6581,40 +6722,26 @@ ath_parent(struct ieee80211com *ic) * torn down much of our state. There's * probably a better way to deal with this. */ + if (!sc->sc_invalid) + ath_init(sc); /* XXX lose error */ + } else { + ATH_LOCK(sc); + ath_stop_locked(ifp); + if (!sc->sc_invalid) + ath_power_setpower(sc, HAL_PM_FULL_SLEEP); ATH_UNLOCK(sc); - ath_init(sc); /* XXX lose error */ - return; } - } else { - ath_stop_locked(sc); - if (!sc->sc_invalid) - ath_power_setpower(sc, HAL_PM_FULL_SLEEP); - } - ATH_UNLOCK(sc); -} - -static int -ath_ioctl(struct ieee80211com *ic, u_long cmd, void *data) -{ - struct ifreq *ifr = data; - struct ath_softc *sc = ic->ic_softc; - - switch (cmd) { - case SIOCGATHSTATS: { - struct ieee80211vap *vap; - struct ifnet *ifp; - const HAL_RATE_TABLE *rt; - + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCGATHSTATS: /* NB: embed these numbers to get a consistent view */ - sc->sc_stats.ast_tx_packets = 0; - sc->sc_stats.ast_rx_packets = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - sc->sc_stats.ast_tx_packets += ifp->if_get_counter(ifp, - IFCOUNTER_OPACKETS); - sc->sc_stats.ast_rx_packets += ifp->if_get_counter(ifp, - IFCOUNTER_IPACKETS); - } + sc->sc_stats.ast_tx_packets = ifp->if_get_counter(ifp, + IFCOUNTER_OPACKETS); + sc->sc_stats.ast_rx_packets = ifp->if_get_counter(ifp, + IFCOUNTER_IPACKETS); sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi); sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi); #ifdef IEEE80211_SUPPORT_TDMA @@ -6628,13 +6755,10 @@ ath_ioctl(struct ieee80211com *ic, u_long cmd, void *data) sc->sc_stats.ast_tx_rate |= IEEE80211_RATE_MCS; return copyout(&sc->sc_stats, ifr->ifr_data, sizeof (sc->sc_stats)); - } case SIOCGATHAGSTATS: return copyout(&sc->sc_aggr_stats, ifr->ifr_data, sizeof (sc->sc_aggr_stats)); - case SIOCZATHSTATS: { - int error; - + case SIOCZATHSTATS: error = priv_check(curthread, PRIV_DRIVER); if (error == 0) { memset(&sc->sc_stats, 0, sizeof(sc->sc_stats)); @@ -6643,21 +6767,30 @@ ath_ioctl(struct ieee80211com *ic, u_long cmd, void *data) memset(&sc->sc_intr_stats, 0, sizeof(sc->sc_intr_stats)); } - return (error); - } + break; #ifdef ATH_DIAGAPI case SIOCGATHDIAG: - return (ath_ioctl_diag(sc, data)); + error = ath_ioctl_diag(sc, (struct ath_diag *) ifr); + break; case SIOCGATHPHYERR: - return (ath_ioctl_phyerr(sc, data)); + error = ath_ioctl_phyerr(sc,(struct ath_diag*) ifr); + break; #endif case SIOCGATHSPECTRAL: - return (ath_ioctl_spectral(sc, data)); + error = ath_ioctl_spectral(sc,(struct ath_diag*) ifr); + break; case SIOCGATHNODERATESTATS: - return (ath_ioctl_ratestats(sc, data)); + error = ath_ioctl_ratestats(sc, (struct ath_rateioctl *) ifr); + break; + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; default: - return (ENOTTY); + error = EINVAL; + break; } + return error; +#undef IS_RUNNING } /* @@ -6698,7 +6831,8 @@ static void ath_dfs_tasklet(void *p, int npending) { struct ath_softc *sc = (struct ath_softc *) p; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; /* * If previous processing has found a radar event, @@ -6730,7 +6864,7 @@ ath_node_powersave(struct ieee80211_node *ni, int enable) #ifdef ATH_SW_PSQ struct ath_node *an = ATH_NODE(ni); struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_vap *avp = ATH_VAP(ni->ni_vap); /* XXX and no TXQ locks should be held here */ @@ -6797,7 +6931,7 @@ ath_node_set_tim(struct ieee80211_node *ni, int enable) { #ifdef ATH_SW_PSQ struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_node *an = ATH_NODE(ni); struct ath_vap *avp = ATH_VAP(ni->ni_vap); int changed = 0; @@ -7002,7 +7136,7 @@ ath_node_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m) struct ath_node *an; struct ath_vap *avp; struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; int tid; /* Just paranoia */ diff --git a/sys/dev/ath/if_ath_beacon.c b/sys/dev/ath/if_ath_beacon.c index 41267b3..a672c71 100644 --- a/sys/dev/ath/if_ath_beacon.c +++ b/sys/dev/ath/if_ath_beacon.c @@ -134,7 +134,7 @@ int ath_beaconq_config(struct ath_softc *sc) { #define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; HAL_TXQ_INFO qi; @@ -464,7 +464,7 @@ ath_beacon_proc(void *arg, int pending) } if (sc->sc_stagbeacons) { /* staggered beacons */ - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint32_t tsftu; tsftu = ath_hal_gettsf32(ah) >> 10; @@ -917,7 +917,7 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) #define FUDGE 2 struct ath_hal *ah = sc->sc_ah; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211_node *ni; u_int32_t nexttbtt, intval, tsftu; u_int32_t nexttbtt_u8, intval_u8; diff --git a/sys/dev/ath/if_ath_debug.h b/sys/dev/ath/if_ath_debug.h index 05d3cf5..40c0b9a 100644 --- a/sys/dev/ath/if_ath_debug.h +++ b/sys/dev/ath/if_ath_debug.h @@ -91,7 +91,9 @@ enum { extern uint64_t ath_debug; -#define IFF_DUMPPKTS(sc, m) ((sc->sc_debug & (m)) +#define IFF_DUMPPKTS(sc, m) \ + ((sc->sc_debug & (m)) || \ + (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) #define DPRINTF(sc, m, fmt, ...) do { \ if (sc->sc_debug & (m)) \ device_printf(sc->sc_dev, fmt, __VA_ARGS__); \ @@ -110,7 +112,8 @@ extern void ath_printtxstatbuf(struct ath_softc *sc, const struct ath_buf *bf, #else /* ATH_DEBUG */ #define ATH_KTR(_sc, _km, _kf, ...) do { } while (0) -#define IFF_DUMPPKTS(sc, m) (0) +#define IFF_DUMPPKTS(sc, m) \ + ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) #define DPRINTF(sc, m, fmt, ...) do { \ (void) sc; \ } while (0) diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c index b8a77e8..fe99f10 100644 --- a/sys/dev/ath/if_ath_keycache.c +++ b/sys/dev/ath/if_ath_keycache.c @@ -425,7 +425,7 @@ int ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) { - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; /* * Group key allocation must be handled specially for @@ -493,7 +493,7 @@ ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, int ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) { - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; const struct ieee80211_cipher *cip = k->wk_cipher; u_int keyix = k->wk_keyix; @@ -538,7 +538,7 @@ int ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, const u_int8_t mac[IEEE80211_ADDR_LEN]) { - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; return ath_keyset(sc, vap, k, vap->iv_bss); } diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h index ff9a4db..711e69e8 100644 --- a/sys/dev/ath/if_ath_misc.h +++ b/sys/dev/ath/if_ath_misc.h @@ -65,7 +65,7 @@ extern void ath_freebuf(struct ath_softc *sc, struct ath_buf *bf); extern void ath_returnbuf_head(struct ath_softc *sc, struct ath_buf *bf); extern void ath_returnbuf_tail(struct ath_softc *sc, struct ath_buf *bf); -extern int ath_reset(struct ath_softc *, ATH_RESET_TYPE); +extern int ath_reset(struct ifnet *, ATH_RESET_TYPE); extern void ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf, int fail); extern void ath_tx_update_ratectrl(struct ath_softc *sc, diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index 600d0a5..2779b7a 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -154,7 +154,8 @@ __FBSDID("$FreeBSD$"); u_int32_t ath_calcrxfilter(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; u_int32_t rfilt; rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; @@ -163,7 +164,7 @@ ath_calcrxfilter(struct ath_softc *sc) if (ic->ic_opmode != IEEE80211_M_STA) rfilt |= HAL_RX_FILTER_PROBEREQ; /* XXX ic->ic_monvaps != 0? */ - if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_promisc > 0) + if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; /* @@ -329,7 +330,7 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; - struct ath_softc *sc = vap->iv_ic->ic_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; uint64_t tsf_beacon_old, tsf_beacon; uint64_t nexttbtt; int64_t tsf_delta; @@ -462,9 +463,10 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, #ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT static void -ath_rx_tap_vendor(struct ath_softc *sc, struct mbuf *m, +ath_rx_tap_vendor(struct ifnet *ifp, struct mbuf *m, const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf) { + struct ath_softc *sc = ifp->if_softc; /* Fill in the extension bitmap */ sc->sc_rx_th.wr_ext_bitmap = htole32(1 << ATH_RADIOTAP_VENDOR_HEADER); @@ -527,13 +529,14 @@ ath_rx_tap_vendor(struct ath_softc *sc, struct mbuf *m, #endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */ static void -ath_rx_tap(struct ath_softc *sc, struct mbuf *m, +ath_rx_tap(struct ifnet *ifp, struct mbuf *m, const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf) { #define CHAN_HT20 htole32(IEEE80211_CHAN_HT20) #define CHAN_HT40U htole32(IEEE80211_CHAN_HT40U) #define CHAN_HT40D htole32(IEEE80211_CHAN_HT40D) #define CHAN_HT (CHAN_HT20|CHAN_HT40U|CHAN_HT40D) + struct ath_softc *sc = ifp->if_softc; const HAL_RATE_TABLE *rt; uint8_t rix; @@ -557,7 +560,7 @@ ath_rx_tap(struct ath_softc *sc, struct mbuf *m, else if (IEEE80211_IS_CHAN_HT20(sc->sc_curchan)) sc->sc_rx_th.wr_chan_flags |= CHAN_HT20; } else if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */ - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; if ((rs->rs_flags & HAL_RX_2040) == 0) sc->sc_rx_th.wr_chan_flags |= CHAN_HT20; @@ -614,7 +617,8 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status, { uint64_t rstamp; int len, type; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni; int is_good = 0; struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; @@ -700,7 +704,7 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status, rs->rs_keyix-32 : rs->rs_keyix); } } - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); rx_error: /* * Cleanup any pending partial frame. @@ -720,9 +724,9 @@ rx_error: /* NB: bpf needs the mbuf length setup */ len = rs->rs_datalen; m->m_pkthdr.len = m->m_len = len; - ath_rx_tap(sc, m, rs, rstamp, nf); + ath_rx_tap(ifp, m, rs, rstamp, nf); #ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT - ath_rx_tap_vendor(sc, m, rs, rstamp, nf); + ath_rx_tap_vendor(ifp, m, rs, rstamp, nf); #endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */ ieee80211_radiotap_rx_all(ic, m); } @@ -745,6 +749,7 @@ rx_accept: sc->sc_stats.ast_rx_toobig++; m_freem(re->m_rxpending); } + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; re->m_rxpending = m; m = NULL; @@ -761,8 +766,10 @@ rx_accept: re->m_rxpending = NULL; } else { /* - * Normal single-descriptor receive; setup packet length. + * Normal single-descriptor receive; setup + * the rcvif and packet length. */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; } @@ -823,6 +830,7 @@ rx_accept: rs->rs_antenna |= 0x4; } + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); sc->sc_stats.ast_ant_rx[rs->rs_antenna]++; /* @@ -833,9 +841,9 @@ rx_accept: * noise setting is filled in above. */ if (ieee80211_radiotap_active(ic)) { - ath_rx_tap(sc, m, rs, rstamp, nf); + ath_rx_tap(ifp, m, rs, rstamp, nf); #ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT - ath_rx_tap_vendor(sc, m, rs, rstamp, nf); + ath_rx_tap_vendor(ifp, m, rs, rstamp, nf); #endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */ } @@ -983,9 +991,10 @@ ath_rx_proc(struct ath_softc *sc, int resched) ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) struct ath_buf *bf; + struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; #ifdef IEEE80211_SUPPORT_SUPERG - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; #endif struct ath_desc *ds; struct ath_rx_status *rs; @@ -1180,10 +1189,15 @@ rx_proc_next: ATH_PCU_UNLOCK(sc); } + /* XXX check this inside of IF_LOCK? */ + if (resched && (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { #ifdef IEEE80211_SUPPORT_SUPERG - if (resched) ieee80211_ff_age_all(ic, 100); #endif + if (!IFQ_IS_EMPTY(&ifp->if_snd)) + ath_tx_kick(sc); + } +#undef PA2DESC /* * Put the hardware to sleep again if we're done with it. @@ -1205,7 +1219,7 @@ rx_proc_next: sc->sc_rxproc_cnt--; ATH_PCU_UNLOCK(sc); } -#undef PA2DESC + #undef ATH_RX_MAX /* diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c index c3e8d3a..7aa818f 100644 --- a/sys/dev/ath/if_ath_rx_edma.c +++ b/sys/dev/ath/if_ath_rx_edma.c @@ -579,8 +579,9 @@ static void ath_edma_recv_tasklet(void *arg, int npending) { struct ath_softc *sc = (struct ath_softc *) arg; + struct ifnet *ifp = sc->sc_ifp; #ifdef IEEE80211_SUPPORT_SUPERG - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; #endif DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: called; npending=%d\n", @@ -616,9 +617,14 @@ ath_edma_recv_tasklet(void *arg, int npending) ath_power_restore_power_state(sc); ATH_UNLOCK(sc); + /* XXX inside IF_LOCK ? */ + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { #ifdef IEEE80211_SUPPORT_SUPERG - ieee80211_ff_age_all(ic, 100); + ieee80211_ff_age_all(ic, 100); #endif + if (! IFQ_IS_EMPTY(&ifp->if_snd)) + ath_tx_kick(sc); + } if (ath_dfs_tasklet_needed(sc, sc->sc_curchan)) taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask); diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index d8c6bac..eeb8d4b 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -367,6 +367,7 @@ static int ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS) { struct ath_softc *sc = arg1; + struct ifnet *ifp = sc->sc_ifp; u_int32_t scale; int error; @@ -380,7 +381,8 @@ ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS) goto finish; error = !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL : - (sc->sc_running) ? ath_reset(sc, ATH_RESET_NOLOSS) : 0; + (ifp->if_drv_flags & IFF_DRV_RUNNING) ? + ath_reset(ifp, ATH_RESET_NOLOSS) : 0; finish: ATH_LOCK(sc); @@ -420,6 +422,7 @@ static int ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) { struct ath_softc *sc = arg1; + struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; u_int rfkill; int error; @@ -441,7 +444,8 @@ ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) error = EINVAL; goto finish; } - error = sc->sc_running ? ath_reset(sc, ATH_RESET_FULL) : 0; + error = (ifp->if_drv_flags & IFF_DRV_RUNNING) ? + ath_reset(ifp, ATH_RESET_FULL) : 0; finish: ATH_LOCK(sc); @@ -667,8 +671,8 @@ ath_sysctl_intmit(SYSCTL_HANDLER_ARGS) * doesn't reset ANI related registers, so it'll leave * things in an inconsistent state. */ - if (sc->sc_running) - ath_reset(sc, ATH_RESET_NOLOSS); + if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) + ath_reset(sc->sc_ifp, ATH_RESET_NOLOSS); error = 0; diff --git a/sys/dev/ath/if_ath_tdma.c b/sys/dev/ath/if_ath_tdma.c index d4c9ccd..fd23db1 100644 --- a/sys/dev/ath/if_ath_tdma.c +++ b/sys/dev/ath/if_ath_tdma.c @@ -359,7 +359,7 @@ ath_tdma_update(struct ieee80211_node *ni, #define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; const HAL_RATE_TABLE *rt = sc->sc_currates; u_int64_t tsf, rstamp, nextslot, nexttbtt, nexttbtt_full; diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c index bee6320..c15b158 100644 --- a/sys/dev/ath/if_ath_tx.c +++ b/sys/dev/ath/if_ath_tx.c @@ -1051,7 +1051,8 @@ ath_tx_calc_protection(struct ath_softc *sc, struct ath_buf *bf) uint16_t flags; int shortPreamble; const HAL_RATE_TABLE *rt = sc->sc_currates; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; flags = bf->bf_state.bfs_txflags; rix = bf->bf_state.bfs_rc[0].rix; @@ -1544,7 +1545,8 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni, { struct ieee80211vap *vap = ni->ni_vap; struct ath_hal *ah = sc->sc_ah; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; int error, iswep, ismcast, isfrag, ismrr; int keyix, hdrlen, pktlen, try0 = 0; @@ -2072,7 +2074,8 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, struct mbuf *m0, const struct ieee80211_bpf_params *params) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ath_hal *ah = sc->sc_ah; struct ieee80211vap *vap = ni->ni_vap; int error, ismcast, ismrr; @@ -2337,7 +2340,8 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; struct ath_buf *bf; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); int error = 0; @@ -2360,9 +2364,10 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, ATH_TX_LOCK(sc); - if (!sc->sc_running || sc->sc_invalid) { - DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, r/i: %d/%d", - __func__, sc->sc_running, sc->sc_invalid); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, %s", __func__, + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ? + "!running" : "invalid"); m_freem(m); error = ENETDOWN; goto bad; @@ -2419,6 +2424,7 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, } } sc->sc_wd_timer = 5; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); sc->sc_stats.ast_tx_raw++; /* @@ -2467,6 +2473,7 @@ bad: badbad: ATH_KTR(sc, ATH_KTR_TX, 2, "ath_raw_xmit: bad0: m=%p, params=%p", m, params); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); sc->sc_stats.ast_tx_raw_fail++; ieee80211_free_node(ni); @@ -5724,7 +5731,7 @@ int ath_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int dialogtoken, int baparamset, int batimeout) { - struct ath_softc *sc = ni->ni_ic->ic_softc; + struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc; int tid = tap->txa_tid; struct ath_node *an = ATH_NODE(ni); struct ath_tid *atid = &an->an_tid[tid]; @@ -5802,7 +5809,7 @@ int ath_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status, int code, int batimeout) { - struct ath_softc *sc = ni->ni_ic->ic_softc; + struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc; int tid = tap->txa_tid; struct ath_node *an = ATH_NODE(ni); struct ath_tid *atid = &an->an_tid[tid]; @@ -5849,7 +5856,7 @@ ath_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, void ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { - struct ath_softc *sc = ni->ni_ic->ic_softc; + struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc; int tid = tap->txa_tid; struct ath_node *an = ATH_NODE(ni); struct ath_tid *atid = &an->an_tid[tid]; @@ -5984,7 +5991,7 @@ void ath_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status) { - struct ath_softc *sc = ni->ni_ic->ic_softc; + struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc; int tid = tap->txa_tid; struct ath_node *an = ATH_NODE(ni); struct ath_tid *atid = &an->an_tid[tid]; @@ -6057,7 +6064,7 @@ void ath_addba_response_timeout(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { - struct ath_softc *sc = ni->ni_ic->ic_softc; + struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc; int tid = tap->txa_tid; struct ath_node *an = ATH_NODE(ni); struct ath_tid *atid = &an->an_tid[tid]; diff --git a/sys/dev/ath/if_ath_tx_edma.c b/sys/dev/ath/if_ath_tx_edma.c index fdc2b4b..7d14920 100644 --- a/sys/dev/ath/if_ath_tx_edma.c +++ b/sys/dev/ath/if_ath_tx_edma.c @@ -537,6 +537,7 @@ ath_edma_dma_txteardown(struct ath_softc *sc) static void ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) { + struct ifnet *ifp = sc->sc_ifp; int i; DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); @@ -578,6 +579,9 @@ ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) /* XXX dump out the frames */ + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); sc->sc_wd_timer = 0; } @@ -830,6 +834,12 @@ ath_edma_tx_processq(struct ath_softc *sc, int dosched) sc->sc_wd_timer = 0; + if (idx > 0) { + IF_LOCK(&sc->sc_ifp->if_snd); + sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&sc->sc_ifp->if_snd); + } + /* Kick software scheduler */ /* * XXX It's inefficient to do this if the FIFO queue is full, diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 2e71ff6..5c5e6cd 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -555,8 +555,8 @@ struct ath_tx_methods { }; struct ath_softc { - struct ieee80211com sc_ic; - struct ath_stats sc_stats; /* device statistics */ + struct ifnet *sc_ifp; /* interface common */ + struct ath_stats sc_stats; /* interface statistics */ struct ath_tx_aggr_stats sc_aggr_stats; struct ath_intr_stats sc_intr_stats; uint64_t sc_debug; @@ -650,8 +650,7 @@ struct ath_softc { /* * Second set of flags. */ - u_int32_t sc_running : 1, /* initialized */ - sc_use_ent : 1, + u_int32_t sc_use_ent : 1, sc_rx_stbc : 1, sc_tx_stbc : 1, sc_hasenforcetxop : 1, /* support enforce TxOP */ diff --git a/sys/dev/bwi/bwimac.c b/sys/dev/bwi/bwimac.c index baad7fe..f39ef44 100644 --- a/sys/dev/bwi/bwimac.c +++ b/sys/dev/bwi/bwimac.c @@ -832,11 +832,11 @@ bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw, uint8_t fw_type) { const struct bwi_fwhdr *hdr; + struct ifnet *ifp = sc->sc_ifp; if (fw->datasize < sizeof(*hdr)) { - device_printf(sc->sc_dev, - "invalid firmware (%s): invalid size %zu\n", - fw->name, fw->datasize); + if_printf(ifp, "invalid firmware (%s): invalid size %zu\n", + fw->name, fw->datasize); return 0; } @@ -847,26 +847,25 @@ bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw, * Don't verify IV's size, it has different meaning */ if (be32toh(hdr->fw_size) != fw->datasize - sizeof(*hdr)) { - device_printf(sc->sc_dev, - "invalid firmware (%s): size mismatch, " - "fw %u, real %zu\n", fw->name, - be32toh(hdr->fw_size), fw->datasize - sizeof(*hdr)); + if_printf(ifp, "invalid firmware (%s): size mismatch, " + "fw %u, real %zu\n", fw->name, + be32toh(hdr->fw_size), + fw->datasize - sizeof(*hdr)); return 0; } } if (hdr->fw_type != fw_type) { - device_printf(sc->sc_dev, - "invalid firmware (%s): type mismatch, " - "fw \'%c\', target \'%c\'\n", fw->name, - hdr->fw_type, fw_type); + if_printf(ifp, "invalid firmware (%s): type mismatch, " + "fw \'%c\', target \'%c\'\n", fw->name, + hdr->fw_type, fw_type); return 0; } if (hdr->fw_gen != BWI_FW_GEN_1) { - device_printf(sc->sc_dev, - "invalid firmware (%s): wrong generation, " - "fw %d, target %d\n", fw->name, hdr->fw_gen, BWI_FW_GEN_1); + if_printf(ifp, "invalid firmware (%s): wrong generation, " + "fw %d, target %d\n", fw->name, + hdr->fw_gen, BWI_FW_GEN_1); return 0; } return 1; @@ -1003,6 +1002,7 @@ static int bwi_mac_fw_load(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; + struct ifnet *ifp = sc->sc_ifp; const uint32_t *fw; uint16_t fw_rev; int fw_len, i; @@ -1057,8 +1057,7 @@ bwi_mac_fw_load(struct bwi_mac *mac) DELAY(10); } if (i == NRETRY) { - device_printf(sc->sc_dev, - "firmware (ucode&pcm) loading timed out\n"); + if_printf(ifp, "firmware (ucode&pcm) loading timed out\n"); return ETIMEDOUT; } @@ -1068,14 +1067,12 @@ bwi_mac_fw_load(struct bwi_mac *mac) fw_rev = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWREV); if (fw_rev > BWI_FW_VERSION3_REVMAX) { - device_printf(sc->sc_dev, - "firmware version 4 is not supported yet\n"); + if_printf(ifp, "firmware version 4 is not supported yet\n"); return ENODEV; } - device_printf(sc->sc_dev, - "firmware rev 0x%04x, patch level 0x%04x\n", fw_rev, - MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV)); + if_printf(ifp, "firmware rev 0x%04x, patch level 0x%04x\n", fw_rev, + MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV)); return 0; } @@ -1135,6 +1132,7 @@ static int bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) { struct bwi_softc *sc = mac->mac_sc; + struct ifnet *ifp = sc->sc_ifp; const struct bwi_fwhdr *hdr; const struct bwi_fw_iv *iv; int n, i, iv_img_size; @@ -1157,7 +1155,7 @@ bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) int sz = 0; if (iv_img_size < sizeof(iv->iv_ofs)) { - device_printf(sc->sc_dev, "invalid IV image, ofs\n"); + if_printf(ifp, "invalid IV image, ofs\n"); return EINVAL; } iv_img_size -= sizeof(iv->iv_ofs); @@ -1167,7 +1165,7 @@ bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) ofs = __SHIFTOUT(iv_ofs, BWI_FW_IV_OFS_MASK); if (ofs >= 0x1000) { - device_printf(sc->sc_dev, "invalid ofs (0x%04x) " + if_printf(ifp, "invalid ofs (0x%04x) " "for %dth iv\n", ofs, i); return EINVAL; } @@ -1176,8 +1174,7 @@ bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) uint32_t val32; if (iv_img_size < sizeof(iv->iv_val.val32)) { - device_printf(sc->sc_dev, - "invalid IV image, val32\n"); + if_printf(ifp, "invalid IV image, val32\n"); return EINVAL; } iv_img_size -= sizeof(iv->iv_val.val32); @@ -1189,8 +1186,7 @@ bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) uint16_t val16; if (iv_img_size < sizeof(iv->iv_val.val16)) { - device_printf(sc->sc_dev, - "invalid IV image, val16\n"); + if_printf(ifp, "invalid IV image, val16\n"); return EINVAL; } iv_img_size -= sizeof(iv->iv_val.val16); @@ -1204,8 +1200,7 @@ bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) } if (iv_img_size != 0) { - device_printf(sc->sc_dev, "invalid IV image, size left %d\n", - iv_img_size); + if_printf(ifp, "invalid IV image, size left %d\n", iv_img_size); return EINVAL; } return 0; @@ -1214,19 +1209,19 @@ bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) static int bwi_mac_fw_init(struct bwi_mac *mac) { - device_t dev = mac->mac_sc->sc_dev; + struct ifnet *ifp = mac->mac_sc->sc_ifp; int error; error = bwi_mac_fw_load_iv(mac, mac->mac_iv); if (error) { - device_printf(dev, "load IV failed\n"); + if_printf(ifp, "load IV failed\n"); return error; } if (mac->mac_iv_ext != NULL) { error = bwi_mac_fw_load_iv(mac, mac->mac_iv_ext); if (error) - device_printf(dev, "load ExtIV failed\n"); + if_printf(ifp, "load ExtIV failed\n"); } return error; } @@ -1235,7 +1230,8 @@ static void bwi_mac_opmode_init(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t mac_status; uint16_t pre_tbtt; @@ -1284,7 +1280,7 @@ bwi_mac_opmode_init(struct bwi_mac *mac) break; } - if (ic->ic_promisc > 0) + if (ic->ic_ifp->if_flags & IFF_PROMISC) mac_status |= BWI_MAC_STATUS_PROMISC; CSR_WRITE_4(sc, BWI_MAC_STATUS, mac_status); @@ -1335,7 +1331,8 @@ bwi_mac_bss_param_init(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; struct bwi_phy *phy = &mac->mac_phy; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct ieee80211_rate_table *rt; struct bwi_retry_lim lim; uint16_t cw_min; @@ -1918,7 +1915,8 @@ static void bwi_mac_lock(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; KASSERT((mac->mac_flags & BWI_MAC_F_LOCKED) == 0, ("mac_flags 0x%x", mac->mac_flags)); @@ -1941,7 +1939,8 @@ static void bwi_mac_unlock(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; KASSERT(mac->mac_flags & BWI_MAC_F_LOCKED, ("mac_flags 0x%x", mac->mac_flags)); diff --git a/sys/dev/bwi/bwiphy.c b/sys/dev/bwi/bwiphy.c index 60d6bf5..1057a83 100644 --- a/sys/dev/bwi/bwiphy.c +++ b/sys/dev/bwi/bwiphy.c @@ -429,7 +429,7 @@ static void bwi_phy_init_11b_rev2(struct bwi_mac *mac) { /* TODO:11B */ - device_printf(mac->mac_sc->sc_dev, + if_printf(mac->mac_sc->sc_ifp, "%s is not implemented yet\n", __func__); } diff --git a/sys/dev/bwi/bwirf.c b/sys/dev/bwi/bwirf.c index 615e6df..cd0723a 100644 --- a/sys/dev/bwi/bwirf.c +++ b/sys/dev/bwi/bwirf.c @@ -1260,6 +1260,7 @@ static void bwi_rf_lo_update_11g(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; + struct ifnet *ifp = sc->sc_ifp; struct bwi_rf *rf = &mac->mac_rf; struct bwi_phy *phy = &mac->mac_phy; struct bwi_tpctl *tpctl = &mac->mac_tpctl; @@ -1328,7 +1329,7 @@ bwi_rf_lo_update_11g(struct bwi_mac *mac) PHY_WRITE(mac, 0x812, 0xb2); } - if ((sc->sc_flags & BWI_F_RUNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) tpctl->tp_ctrl2 = bwi_rf_get_tp_ctrl2(mac); PHY_WRITE(mac, 0x80f, 0x8078); @@ -1351,7 +1352,7 @@ bwi_rf_lo_update_11g(struct bwi_mac *mac) PHY_WRITE(mac, 0x15, devi_ctrl | 0xefa0); } - if ((sc->sc_flags & BWI_F_RUNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) tpctl = NULL; bwi_rf_lo_adjust(mac, tpctl); @@ -1461,7 +1462,7 @@ _bwi_rf_lo_update_11g(struct bwi_mac *mac, uint16_t orig_rf7a) static const int rf_lo_measure_order[RF_ATTEN_LISTSZ] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8, 10, 11, 12, 13 }; - struct bwi_softc *sc = mac->mac_sc; + struct ifnet *ifp = mac->mac_sc->sc_ifp; struct bwi_rf_lo lo_save, *lo; uint8_t devi_ctrl = 0; int idx, adj_rf7a = 0; @@ -1475,7 +1476,7 @@ _bwi_rf_lo_update_11g(struct bwi_mac *mac, uint16_t orig_rf7a) for (bbp_atten = 0; bbp_atten < BBP_ATTEN_MAX; ++bbp_atten) { uint16_t tp_ctrl2, rf7a; - if ((sc->sc_flags & BWI_F_RUNNING) == 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { if (idx == 0) { bzero(&lo_save, sizeof(lo_save)); } else if (init_rf_atten < 0) { diff --git a/sys/dev/bwi/if_bwi.c b/sys/dev/bwi/if_bwi.c index 741f5f1..ad41bc6 100644 --- a/sys/dev/bwi/if_bwi.c +++ b/sys/dev/bwi/if_bwi.c @@ -102,10 +102,10 @@ static struct ieee80211vap *bwi_vap_create(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void bwi_vap_delete(struct ieee80211vap *); -static void bwi_init(struct bwi_softc *); -static void bwi_parent(struct ieee80211com *); -static int bwi_transmit(struct ieee80211com *, struct mbuf *); -static void bwi_start_locked(struct bwi_softc *); +static void bwi_init(void *); +static int bwi_ioctl(struct ifnet *, u_long, caddr_t); +static void bwi_start(struct ifnet *); +static void bwi_start_locked(struct ifnet *); static int bwi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void bwi_watchdog(void *); @@ -352,12 +352,14 @@ bwi_setup_desc32(struct bwi_softc *sc, struct bwi_desc32 *desc_array, int bwi_attach(struct bwi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; device_t dev = sc->sc_dev; + struct ifnet *ifp; struct bwi_mac *mac; struct bwi_phy *phy; int i, error; uint8_t bands; + uint8_t macaddr[IEEE80211_ADDR_LEN]; BWI_LOCK_INIT(sc); @@ -369,8 +371,8 @@ bwi_attach(struct bwi_softc *sc) taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", device_get_nameunit(dev)); TASK_INIT(&sc->sc_restart_task, 0, bwi_restart, sc); + callout_init_mtx(&sc->sc_calib_ch, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* * Initialize sysctl variables @@ -448,6 +450,25 @@ bwi_attach(struct bwi_softc *sc) if (error) goto fail; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + error = ENOSPC; + goto fail; + } + ic = ifp->if_l2com; + + /* set these up early for if_printf use */ + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = bwi_init; + ifp->if_ioctl = bwi_ioctl; + ifp->if_start = bwi_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); /* @@ -464,13 +485,13 @@ bwi_attach(struct bwi_softc *sc) setbit(&bands, IEEE80211_MODE_11G); } - bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, ic->ic_macaddr); - if (IEEE80211_IS_MULTICAST(ic->ic_macaddr)) { - bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, ic->ic_macaddr); - if (IEEE80211_IS_MULTICAST(ic->ic_macaddr)) { + bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, macaddr); + if (IEEE80211_IS_MULTICAST(macaddr)) { + bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, macaddr); + if (IEEE80211_IS_MULTICAST(macaddr)) { device_printf(dev, "invalid MAC address: %6D\n", - ic->ic_macaddr, ":"); + macaddr, ":"); } } } else if (phy->phy_mode == IEEE80211_MODE_11A) { @@ -489,6 +510,7 @@ bwi_attach(struct bwi_softc *sc) /* XXX use locale */ ieee80211_init_channels(ic, NULL, &bands); + ic->ic_ifp = ifp; ic->ic_softc = sc; ic->ic_name = device_get_nameunit(dev); ic->ic_caps = IEEE80211_C_STA | @@ -498,7 +520,7 @@ bwi_attach(struct bwi_softc *sc) IEEE80211_C_BGSCAN | IEEE80211_C_MONITOR; ic->ic_opmode = IEEE80211_M_STA; - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_headroom = sizeof(struct bwi_txbuf_hdr); @@ -510,8 +532,6 @@ bwi_attach(struct bwi_softc *sc) ic->ic_scan_start = bwi_scan_start; ic->ic_scan_end = bwi_scan_end; ic->ic_set_channel = bwi_set_channel; - ic->ic_transmit = bwi_transmit; - ic->ic_parent = bwi_parent; sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); @@ -557,7 +577,8 @@ fail: int bwi_detach(struct bwi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int i; bwi_stop(sc, 1); @@ -569,8 +590,8 @@ bwi_detach(struct bwi_softc *sc) for (i = 0; i < sc->sc_nmac; ++i) bwi_mac_detach(&sc->sc_mac[i]); bwi_dma_free(sc); + if_free(ifp); taskqueue_free(sc->sc_tq); - mbufq_drain(&sc->sc_snd); BWI_LOCK_DESTROY(sc); @@ -588,11 +609,14 @@ bwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - bvp = malloc(sizeof(struct bwi_vap), M_80211_VAP, M_WAITOK | M_ZERO); + bvp = (struct bwi_vap *) malloc(sizeof(struct bwi_vap), + M_80211_VAP, M_WAITOK | M_ZERO); + if (bvp == NULL) + return NULL; vap = &bvp->bv_vap; /* enable s/w bmiss handling for sta mode */ ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid); + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); /* override default methods */ bvp->bv_newstate = vap->iv_newstate; @@ -603,8 +627,7 @@ bwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* complete setup */ - ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status, - mac); + ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -628,8 +651,9 @@ bwi_suspend(struct bwi_softc *sc) void bwi_resume(struct bwi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; - if (sc->sc_ic.ic_nrunning > 0) + if (ifp->if_flags & IFF_UP) bwi_init(sc); } @@ -1193,26 +1217,27 @@ bwi_set_clock_delay(struct bwi_softc *sc) } static void -bwi_init(struct bwi_softc *sc) +bwi_init(void *xsc) { - struct ieee80211com *ic = &sc->sc_ic; + struct bwi_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; BWI_LOCK(sc); bwi_init_statechg(sc, 1); BWI_UNLOCK(sc); - if (sc->sc_flags & BWI_F_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); /* start all vap's */ } static void bwi_init_statechg(struct bwi_softc *sc, int statechg) { + struct ifnet *ifp = sc->sc_ifp; struct bwi_mac *mac; int error; - BWI_ASSERT_LOCKED(sc); - bwi_stop_locked(sc, statechg); bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); @@ -1222,21 +1247,20 @@ bwi_init_statechg(struct bwi_softc *sc, int statechg) mac = &sc->sc_mac[0]; error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL); if (error) { - device_printf(sc->sc_dev, "%s: error %d on regwin switch\n", + if_printf(ifp, "%s: error %d on regwin switch\n", __func__, error); goto bad; } error = bwi_mac_init(mac); if (error) { - device_printf(sc->sc_dev, "%s: error %d on MAC init\n", - __func__, error); + if_printf(ifp, "%s: error %d on MAC init\n", __func__, error); goto bad; } bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN); bwi_set_bssid(sc, bwi_zero_addr); /* Clear BSSID */ - bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, sc->sc_ic.ic_macaddr); + bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, IF_LLADDR(ifp)); bwi_mac_reset_hwkeys(mac); @@ -1254,8 +1278,7 @@ bwi_init_statechg(struct bwi_softc *sc, int statechg) CSR_READ_4(sc, BWI_TXSTATUS1); } if (i == NRETRY) - device_printf(sc->sc_dev, - "%s: can't drain TX status\n", __func__); + if_printf(ifp, "%s: can't drain TX status\n", __func__); #undef NRETRY } @@ -1265,14 +1288,14 @@ bwi_init_statechg(struct bwi_softc *sc, int statechg) /* Start MAC */ error = bwi_mac_start(mac); if (error) { - device_printf(sc->sc_dev, "%s: error %d starting MAC\n", - __func__, error); + if_printf(ifp, "%s: error %d starting MAC\n", __func__, error); goto bad; } /* Clear stop flag before enabling interrupt */ sc->sc_flags &= ~BWI_F_STOP; - sc->sc_flags |= BWI_F_RUNNING; + + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); /* Enable intrs */ @@ -1282,110 +1305,135 @@ bad: bwi_stop_locked(sc, 1); } -static void -bwi_parent(struct ieee80211com *ic) +static int +bwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct bwi_softc *sc = ic->ic_softc; - int startall = 0; - - BWI_LOCK(sc); - if (ic->ic_nrunning > 0) { - struct bwi_mac *mac; - int promisc = -1; +#define IS_RUNNING(ifp) \ + ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + struct bwi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; - KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, - ("current regwin type %d", - sc->sc_cur_regwin->rw_type)); - mac = (struct bwi_mac *)sc->sc_cur_regwin; + switch (cmd) { + case SIOCSIFFLAGS: + BWI_LOCK(sc); + if (IS_RUNNING(ifp)) { + struct bwi_mac *mac; + int promisc = -1; + + KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, + ("current regwin type %d", + sc->sc_cur_regwin->rw_type)); + mac = (struct bwi_mac *)sc->sc_cur_regwin; + + if ((ifp->if_flags & IFF_PROMISC) && + (sc->sc_flags & BWI_F_PROMISC) == 0) { + promisc = 1; + sc->sc_flags |= BWI_F_PROMISC; + } else if ((ifp->if_flags & IFF_PROMISC) == 0 && + (sc->sc_flags & BWI_F_PROMISC)) { + promisc = 0; + sc->sc_flags &= ~BWI_F_PROMISC; + } - if (ic->ic_promisc > 0 && (sc->sc_flags & BWI_F_PROMISC) == 0) { - promisc = 1; - sc->sc_flags |= BWI_F_PROMISC; - } else if (ic->ic_promisc == 0 && - (sc->sc_flags & BWI_F_PROMISC) != 0) { - promisc = 0; - sc->sc_flags &= ~BWI_F_PROMISC; + if (promisc >= 0) + bwi_mac_set_promisc(mac, promisc); } - if (promisc >= 0) - bwi_mac_set_promisc(mac, promisc); - } - if (ic->ic_nrunning > 0) { - if ((sc->sc_flags & BWI_F_RUNNING) == 0) { - bwi_init_statechg(sc, 1); - startall = 1; + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + bwi_init_statechg(sc, 1); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + bwi_stop_locked(sc, 1); } - } else if (sc->sc_flags & BWI_F_RUNNING) - bwi_stop_locked(sc, 1); - BWI_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + BWI_UNLOCK(sc); + 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; +#undef IS_RUNNING } -static int -bwi_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +bwi_start(struct ifnet *ifp) { - struct bwi_softc *sc = ic->ic_softc; - int error; + struct bwi_softc *sc = ifp->if_softc; BWI_LOCK(sc); - if ((sc->sc_flags & BWI_F_RUNNING) == 0) { - BWI_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - BWI_UNLOCK(sc); - return (error); - } - bwi_start_locked(sc); + bwi_start_locked(ifp); BWI_UNLOCK(sc); - return (0); } static void -bwi_start_locked(struct bwi_softc *sc) +bwi_start_locked(struct ifnet *ifp) { + struct bwi_softc *sc = ifp->if_softc; struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; struct ieee80211_frame *wh; struct ieee80211_node *ni; + struct ieee80211_key *k; struct mbuf *m; int trans, idx; - BWI_ASSERT_LOCKED(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; trans = 0; idx = tbd->tbd_idx; - while (tbd->tbd_buf[idx].tb_mbuf == NULL && - tbd->tbd_used + BWI_TX_NSPRDESC < BWI_TX_NDESC && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + while (tbd->tbd_buf[idx].tb_mbuf == NULL) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ + if (m == NULL) + break; + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; wh = mtod(m, struct ieee80211_frame *); - if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) != 0 && - ieee80211_crypto_encap(ni, m) == NULL) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); - ieee80211_free_node(ni); - m_freem(m); - continue; + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + ieee80211_free_node(ni); + m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + continue; + } } + wh = NULL; /* Catch any invalid use */ + if (bwi_encap(sc, idx, m, ni) != 0) { /* 'm' is freed in bwi_encap() if we reach here */ - if (ni != NULL) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if (ni != NULL) ieee80211_free_node(ni); - } else - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } + trans = 1; tbd->tbd_used++; idx = (idx + 1) % BWI_TX_NDESC; - } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + + if (tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + } tbd->tbd_idx = idx; + if (trans) sc->sc_tx_timer = 5; } @@ -1395,12 +1443,13 @@ bwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct bwi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct bwi_softc *sc = ifp->if_softc; /* XXX wme? */ struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; int idx, error; - if ((sc->sc_flags & BWI_F_RUNNING) == 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { ieee80211_free_node(ni); m_freem(m); return ENETDOWN; @@ -1423,12 +1472,16 @@ bwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, error = bwi_encap_raw(sc, idx, m, ni, params); } if (error == 0) { - tbd->tbd_used++; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if (++tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; tbd->tbd_idx = (idx + 1) % BWI_TX_NDESC; sc->sc_tx_timer = 5; - } else + } else { /* NB: m is reclaimed on encap failure */ ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } BWI_UNLOCK(sc); return error; } @@ -1437,12 +1490,14 @@ static void bwi_watchdog(void *arg) { struct bwi_softc *sc; + struct ifnet *ifp; sc = arg; + ifp = sc->sc_ifp; BWI_ASSERT_LOCKED(sc); if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "watchdog timeout\n"); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_printf(ifp, "watchdog timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); } callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); @@ -1459,6 +1514,7 @@ bwi_stop(struct bwi_softc *sc, int statechg) static void bwi_stop_locked(struct bwi_softc *sc, int statechg) { + struct ifnet *ifp = sc->sc_ifp; struct bwi_mac *mac; int i, error, pwr_off = 0; @@ -1469,7 +1525,7 @@ bwi_stop_locked(struct bwi_softc *sc, int statechg) sc->sc_led_blinking = 0; sc->sc_flags |= BWI_F_STOP; - if (sc->sc_flags & BWI_F_RUNNING) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, ("current regwin type %d", sc->sc_cur_regwin->rw_type)); mac = (struct bwi_mac *)sc->sc_cur_regwin; @@ -1501,13 +1557,14 @@ bwi_stop_locked(struct bwi_softc *sc, int statechg) sc->sc_tx_timer = 0; callout_stop(&sc->sc_watchdog_timer); - sc->sc_flags &= ~BWI_F_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } void bwi_intr(void *xsc) { struct bwi_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; struct bwi_mac *mac; uint32_t intr_status; uint32_t txrx_intr_status[BWI_TXRX_NRING]; @@ -1515,7 +1572,7 @@ bwi_intr(void *xsc) BWI_LOCK(sc); - if ((sc->sc_flags & BWI_F_RUNNING) == 0 || + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || (sc->sc_flags & BWI_F_STOP)) { BWI_UNLOCK(sc); return; @@ -1558,7 +1615,7 @@ bwi_intr(void *xsc) i, txrx_intr_status[i]); if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) { - device_printf(sc->sc_dev, + if_printf(ifp, "%s: intr fatal TX/RX (%d) error 0x%08x\n", __func__, i, txrx_intr_status[i]); txrx_error = 1; @@ -1596,8 +1653,7 @@ bwi_intr(void *xsc) */ if (intr_status & BWI_INTR_PHY_TXERR) { if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) { - device_printf(sc->sc_dev, "%s: intr PHY TX error\n", - __func__); + if_printf(ifp, "%s: intr PHY TX error\n", __func__); taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); BWI_UNLOCK(sc); return; @@ -1612,7 +1668,7 @@ bwi_intr(void *xsc) bwi_mac_config_ps(mac); if (intr_status & BWI_INTR_EO_ATIM) - device_printf(sc->sc_dev, "EO_ATIM\n"); + if_printf(ifp, "EO_ATIM\n"); if (intr_status & BWI_INTR_PMQ) { for (;;) { @@ -1623,7 +1679,7 @@ bwi_intr(void *xsc) } if (intr_status & BWI_INTR_NOISE) - device_printf(sc->sc_dev, "intr noise\n"); + if_printf(ifp, "intr noise\n"); if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) { rx_data = sc->sc_rxeof(sc); @@ -1672,7 +1728,7 @@ bwi_intr(void *xsc) static void bwi_scan_start(struct ieee80211com *ic) { - struct bwi_softc *sc = ic->ic_softc; + struct bwi_softc *sc = ic->ic_ifp->if_softc; BWI_LOCK(sc); /* Enable MAC beacon promiscuity */ @@ -1683,7 +1739,7 @@ bwi_scan_start(struct ieee80211com *ic) static void bwi_set_channel(struct ieee80211com *ic) { - struct bwi_softc *sc = ic->ic_softc; + struct bwi_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_channel *c = ic->ic_curchan; struct bwi_mac *mac; @@ -1709,7 +1765,7 @@ bwi_set_channel(struct ieee80211com *ic) static void bwi_scan_end(struct ieee80211com *ic) { - struct bwi_softc *sc = ic->ic_softc; + struct bwi_softc *sc = ic->ic_ifp->if_softc; BWI_LOCK(sc); CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); @@ -1721,8 +1777,9 @@ bwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct bwi_vap *bvp = BWI_VAP(vap); struct ieee80211com *ic= vap->iv_ic; - struct bwi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; enum ieee80211_state ostate = vap->iv_state; + struct bwi_softc *sc = ifp->if_softc; struct bwi_mac *mac; int error; @@ -2568,7 +2625,8 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx) { struct bwi_ring_data *rd = &sc->sc_rx_rdata; struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int idx, rx_data = 0; idx = rbd->rbd_idx; @@ -2587,7 +2645,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx) BUS_DMASYNC_POSTREAD); if (bwi_newbuf(sc, idx, 0)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto next; } @@ -2601,10 +2659,9 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx) buflen = le16toh(hdr->rxh_buflen); if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) { - device_printf(sc->sc_dev, - "%s: zero length data, hdr_extra %d\n", - __func__, hdr_extra); - counter_u64_add(ic->ic_ierrors, 1); + if_printf(ifp, "%s: zero length data, hdr_extra %d\n", + __func__, hdr_extra); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); m_freem(m); goto next; } @@ -2613,6 +2670,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx) rssi = bwi_calc_rssi(sc, hdr); noise = bwi_calc_noise(sc); + m->m_pkthdr.rcvif = ifp; m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr); m_adj(m, sizeof(*hdr) + wh_ofs); @@ -2746,6 +2804,7 @@ bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) { struct bwi_ring_data *rd; struct bwi_txbuf_data *tbd; + struct ifnet *ifp = sc->sc_ifp; uint32_t state, val; int i; @@ -2766,9 +2825,8 @@ bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) DELAY(1000); } if (i == NRETRY) { - device_printf(sc->sc_dev, - "%s: wait for TX ring(%d) stable timed out\n", - __func__, ring_idx); + if_printf(ifp, "%s: wait for TX ring(%d) stable timed out\n", + __func__, ring_idx); } CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0); @@ -2781,7 +2839,7 @@ bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) DELAY(1000); } if (i == NRETRY) - device_printf(sc->sc_dev, "%s: reset TX ring (%d) timed out\n", + if_printf(ifp, "%s: reset TX ring (%d) timed out\n", __func__, ring_idx); #undef NRETRY @@ -2889,7 +2947,8 @@ bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; @@ -2965,8 +3024,7 @@ bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, */ M_PREPEND(m, sizeof(*hdr), M_NOWAIT); if (m == NULL) { - device_printf(sc->sc_dev, "%s: prepend TX header failed\n", - __func__); + if_printf(ifp, "%s: prepend TX header failed\n", __func__); return ENOBUFS; } hdr = mtod(m, struct bwi_txbuf_hdr *); @@ -3015,7 +3073,7 @@ bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); if (error && error != EFBIG) { - device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n", + if_printf(ifp, "%s: can't load TX buffer (1) %d\n", __func__, error); goto back; } @@ -3025,8 +3083,8 @@ bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, m_new = m_defrag(m, M_NOWAIT); if (m_new == NULL) { - device_printf(sc->sc_dev, - "%s: can't defrag TX buffer\n", __func__); + if_printf(ifp, "%s: can't defrag TX buffer\n", + __func__); error = ENOBUFS; goto back; } else { @@ -3037,8 +3095,7 @@ bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); if (error) { - device_printf(sc->sc_dev, - "%s: can't load TX buffer (2) %d\n", + if_printf(ifp, "%s: can't load TX buffer (2) %d\n", __func__, error); goto back; } @@ -3080,6 +3137,7 @@ static int bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; @@ -3146,8 +3204,7 @@ bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, */ M_PREPEND(m, sizeof(*hdr), M_NOWAIT); if (m == NULL) { - device_printf(sc->sc_dev, "%s: prepend TX header failed\n", - __func__); + if_printf(ifp, "%s: prepend TX header failed\n", __func__); return ENOBUFS; } hdr = mtod(m, struct bwi_txbuf_hdr *); @@ -3195,15 +3252,14 @@ bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, struct mbuf *m_new; if (error != EFBIG) { - device_printf(sc->sc_dev, - "%s: can't load TX buffer (1) %d\n", + if_printf(ifp, "%s: can't load TX buffer (1) %d\n", __func__, error); goto back; } m_new = m_defrag(m, M_NOWAIT); if (m_new == NULL) { - device_printf(sc->sc_dev, - "%s: can't defrag TX buffer\n", __func__); + if_printf(ifp, "%s: can't defrag TX buffer\n", + __func__); error = ENOBUFS; goto back; } @@ -3212,8 +3268,7 @@ bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); if (error) { - device_printf(sc->sc_dev, - "%s: can't load TX buffer (2) %d\n", + if_printf(ifp, "%s: can't load TX buffer (2) %d\n", __func__, error); goto back; } @@ -3257,6 +3312,7 @@ bwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) static void bwi_txeof_status32(struct bwi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; uint32_t val, ctrl_base; int end_idx; @@ -3271,7 +3327,8 @@ bwi_txeof_status32(struct bwi_softc *sc) CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, end_idx * sizeof(struct bwi_desc32)); - bwi_start_locked(sc); + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) + ifp->if_start(ifp); } static void @@ -3283,6 +3340,7 @@ bwi_txeof_status64(struct bwi_softc *sc) static void _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) { + struct ifnet *ifp = sc->sc_ifp; struct bwi_txbuf_data *tbd; struct bwi_txbuf *tb; int ring_idx, buf_idx; @@ -3290,7 +3348,7 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) struct ieee80211vap *vap; if (tx_id == 0) { - device_printf(sc->sc_dev, "%s: zero tx id\n", __func__); + if_printf(ifp, "%s: zero tx id\n", __func__); return; } @@ -3311,7 +3369,8 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap); - if ((ni = tb->tb_ni) != NULL) { + ni = tb->tb_ni; + if (tb->tb_ni != NULL) { const struct bwi_txbuf_hdr *hdr = mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *); vap = ni->ni_vap; @@ -3329,14 +3388,24 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) (data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS : IEEE80211_RATECTL_TX_FAILURE, &acked, NULL); } - ieee80211_tx_complete(ni, tb->tb_mbuf, !acked); + + /* + * Do any tx complete callback. Note this must + * be done before releasing the node reference. + */ + if (tb->tb_mbuf->m_flags & M_TXCB) + ieee80211_process_callback(ni, tb->tb_mbuf, !acked); + + ieee80211_free_node(tb->tb_ni); tb->tb_ni = NULL; - } else - m_freem(tb->tb_mbuf); + } + m_freem(tb->tb_mbuf); tb->tb_mbuf = NULL; if (tbd->tbd_used == 0) sc->sc_tx_timer = 0; + + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static void @@ -3368,6 +3437,7 @@ bwi_txeof_status(struct bwi_softc *sc, int end_idx) static void bwi_txeof(struct bwi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; for (;;) { uint32_t tx_status0, tx_status1; @@ -3390,7 +3460,8 @@ bwi_txeof(struct bwi_softc *sc) data_txcnt); } - bwi_start_locked(sc); + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) + ifp->if_start(ifp); } static int @@ -3638,6 +3709,7 @@ bwi_regwin_enable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) static void bwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) { + struct ifnet *ifp = sc->sc_ifp; struct bwi_mac *mac; struct bwi_myaddr_bssid buf; const uint8_t *p; @@ -3650,7 +3722,7 @@ bwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid); - bcopy(sc->sc_ic.ic_macaddr, buf.myaddr, sizeof(buf.myaddr)); + bcopy(IF_LLADDR(ifp), buf.myaddr, sizeof(buf.myaddr)); bcopy(bssid, buf.bssid, sizeof(buf.bssid)); n = sizeof(buf) / sizeof(val); @@ -3673,7 +3745,7 @@ bwi_updateslot(struct ieee80211com *ic) struct bwi_mac *mac; BWI_LOCK(sc); - if (sc->sc_flags & BWI_F_RUNNING) { + if (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) { DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__); KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, @@ -3689,12 +3761,16 @@ static void bwi_calibrate(void *xsc) { struct bwi_softc *sc = xsc; +#ifdef INVARIANTS + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; +#endif struct bwi_mac *mac; BWI_ASSERT_LOCKED(sc); - KASSERT(sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR, - ("opmode %d", sc->sc_ic.ic_opmode)); + KASSERT(ic->ic_opmode != IEEE80211_M_MONITOR, + ("opmode %d", ic->ic_opmode)); KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, ("current regwin type %d", sc->sc_cur_regwin->rw_type)); @@ -3836,7 +3912,8 @@ bwi_led_onoff(const struct bwi_led *led, uint16_t val, int on) static void bwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t val; int i; @@ -3845,7 +3922,7 @@ bwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) sc->sc_led_blinking = 0; } - if ((sc->sc_flags & BWI_F_RUNNING) == 0) + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); @@ -3973,12 +4050,13 @@ static void bwi_restart(void *xsc, int pending) { struct bwi_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; - device_printf(sc->sc_dev, "%s begin, help!\n", __func__); + if_printf(ifp, "%s begin, help!\n", __func__); BWI_LOCK(sc); - bwi_init_statechg(sc, 0); + bwi_init_statechg(xsc, 0); #if 0 - bwi_start_locked(sc); + bwi_start_locked(ifp); #endif BWI_UNLOCK(sc); } diff --git a/sys/dev/bwi/if_bwivar.h b/sys/dev/bwi/if_bwivar.h index 07c20fe..d5f09da 100644 --- a/sys/dev/bwi/if_bwivar.h +++ b/sys/dev/bwi/if_bwivar.h @@ -541,11 +541,10 @@ struct bwi_vap { #define BWI_VAP(vap) ((struct bwi_vap *)(vap)) struct bwi_softc { + struct ifnet *sc_ifp; uint32_t sc_flags; /* BWI_F_ */ device_t sc_dev; struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mbufq sc_snd; int sc_invalid; uint32_t sc_cap; /* BWI_CAP_ */ @@ -648,7 +647,6 @@ struct bwi_softc { #define BWI_F_BUS_INITED 0x1 #define BWI_F_PROMISC 0x2 #define BWI_F_STOP 0x4 -#define BWI_F_RUNNING 0x8 #define BWI_DBG_MAC 0x00000001 #define BWI_DBG_RF 0x00000002 diff --git a/sys/dev/bwn/if_bwn.c b/sys/dev/bwn/if_bwn.c index 15f6f27..39bd06f 100644 --- a/sys/dev/bwn/if_bwn.c +++ b/sys/dev/bwn/if_bwn.c @@ -133,13 +133,13 @@ static int bwn_wme = 1; SYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0, "uses WME support"); -static void bwn_attach_pre(struct bwn_softc *); +static int bwn_attach_pre(struct bwn_softc *); static int bwn_attach_post(struct bwn_softc *); static void bwn_sprom_bugfixes(device_t); -static int bwn_init(struct bwn_softc *); -static void bwn_parent(struct ieee80211com *); -static void bwn_start(struct bwn_softc *); -static int bwn_transmit(struct ieee80211com *, struct mbuf *); +static void bwn_init(void *); +static int bwn_init_locked(struct bwn_softc *); +static int bwn_ioctl(struct ifnet *, u_long, caddr_t); +static void bwn_start(struct ifnet *); static int bwn_attach_core(struct bwn_mac *); static void bwn_reset_core(struct bwn_mac *, uint32_t); static int bwn_phy_getinfo(struct bwn_mac *, int); @@ -197,7 +197,8 @@ static struct ieee80211vap *bwn_vap_create(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void bwn_vap_delete(struct ieee80211vap *); -static void bwn_stop(struct bwn_softc *); +static void bwn_stop(struct bwn_softc *, int); +static void bwn_stop_locked(struct bwn_softc *, int); static int bwn_core_init(struct bwn_mac *); static void bwn_core_start(struct bwn_mac *); static void bwn_core_exit(struct bwn_mac *); @@ -408,6 +409,7 @@ static void bwn_handle_txeof(struct bwn_mac *, const struct bwn_txstatus *); static void bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *); static void bwn_phy_txpower_check(struct bwn_mac *, uint32_t); +static void bwn_start_locked(struct ifnet *); static int bwn_tx_start(struct bwn_softc *, struct ieee80211_node *, struct mbuf *); static int bwn_tx_isfull(struct bwn_softc *, struct mbuf *); @@ -928,7 +930,9 @@ bwn_attach(device_t dev) #endif if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) { - bwn_attach_pre(sc); + error = bwn_attach_pre(sc); + if (error != 0) + return (error); bwn_sprom_bugfixes(dev); sc->sc_flags |= BWN_FLAG_ATTACHED; } @@ -943,7 +947,10 @@ bwn_attach(device_t dev) } } - mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO); + mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF, + M_NOWAIT | M_ZERO); + if (mac == NULL) + return (ENOMEM); mac->mac_sc = sc; mac->mac_status = BWN_MAC_STATUS_UNINIT; if (bwn_bfp != 0) @@ -1046,8 +1053,11 @@ bwn_is_valid_ether_addr(uint8_t *addr) static int bwn_attach_post(struct bwn_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp = sc->sc_ifp; + ic = ifp->if_l2com; + ic->ic_ifp = ifp; ic->ic_softc = sc; ic->ic_name = device_get_nameunit(sc->sc_dev); /* XXX not right but it's not used anywhere important */ @@ -1067,14 +1077,12 @@ bwn_attach_post(struct bwn_softc *sc) ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; /* s/w bmiss */ - IEEE80211_ADDR_COPY(ic->ic_macaddr, + /* call MI attach routine. */ + ieee80211_ifattach(ic, bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ? siba_sprom_get_mac_80211a(sc->sc_dev) : siba_sprom_get_mac_80211bg(sc->sc_dev)); - /* call MI attach routine. */ - ieee80211_ifattach(ic); - ic->ic_headroom = sizeof(struct bwn_txhdr); /* override default methods */ @@ -1082,13 +1090,13 @@ bwn_attach_post(struct bwn_softc *sc) ic->ic_updateslot = bwn_updateslot; ic->ic_update_promisc = bwn_update_promisc; ic->ic_wme.wme_update = bwn_wme_update; + ic->ic_scan_start = bwn_scan_start; ic->ic_scan_end = bwn_scan_end; ic->ic_set_channel = bwn_set_channel; + ic->ic_vap_create = bwn_vap_create; ic->ic_vap_delete = bwn_vap_delete; - ic->ic_transmit = bwn_transmit; - ic->ic_parent = bwn_parent; ieee80211_radiotap_attach(ic, &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), @@ -1116,24 +1124,26 @@ bwn_detach(device_t dev) { struct bwn_softc *sc = device_get_softc(dev); struct bwn_mac *mac = sc->sc_curmac; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int i; sc->sc_flags |= BWN_FLAG_INVALID; if (device_is_attached(sc->sc_dev)) { - BWN_LOCK(sc); - bwn_stop(sc); - BWN_UNLOCK(sc); + bwn_stop(sc, 1); bwn_dma_free(mac); callout_drain(&sc->sc_led_blink_ch); callout_drain(&sc->sc_rfswitch_ch); callout_drain(&sc->sc_task_ch); callout_drain(&sc->sc_watchdog_ch); bwn_phy_detach(mac); - ieee80211_draintask(ic, &mac->mac_hwreset); - ieee80211_draintask(ic, &mac->mac_txpower); - ieee80211_ifdetach(ic); + if (ifp != NULL) { + ieee80211_draintask(ic, &mac->mac_hwreset); + ieee80211_draintask(ic, &mac->mac_txpower); + ieee80211_ifdetach(ic); + if_free(ifp); + } } taskqueue_drain(sc->sc_tq, &mac->mac_intrtask); taskqueue_free(sc->sc_tq); @@ -1148,25 +1158,52 @@ bwn_detach(device_t dev) bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq); if (mac->mac_msi != 0) pci_release_msi(dev); - mbufq_drain(&sc->sc_snd); + BWN_LOCK_DESTROY(sc); return (0); } -static void +static int bwn_attach_pre(struct bwn_softc *sc) { + struct ifnet *ifp; + int error = 0; BWN_LOCK_INIT(sc); TAILQ_INIT(&sc->sc_maclist); callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); + sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT, taskqueue_thread_enqueue, &sc->sc_tq); taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", device_get_nameunit(sc->sc_dev)); + + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + error = ENOSPC; + goto fail; + } + + /* set these up early for if_printf use */ + if_initname(ifp, device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev)); + + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = bwn_init; + ifp->if_ioctl = bwn_ioctl; + ifp->if_start = bwn_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + return (0); + +fail: BWN_LOCK_DESTROY(sc); + return (error); } static void @@ -1201,51 +1238,58 @@ bwn_sprom_bugfixes(device_t dev) #undef BWN_ISDEV } -static void -bwn_parent(struct ieee80211com *ic) -{ - struct bwn_softc *sc = ic->ic_softc; - int startall = 0; - - BWN_LOCK(sc); - if (ic->ic_nrunning > 0) { - if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) { - bwn_init(sc); - startall = 1; - } else +static int +bwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ +#define IS_RUNNING(ifp) \ + ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + struct bwn_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0, startall; + + switch (cmd) { + case SIOCSIFFLAGS: + startall = 0; + if (IS_RUNNING(ifp)) { bwn_update_promisc(ic); - } else if (sc->sc_flags & BWN_FLAG_RUNNING) - bwn_stop(sc); - BWN_UNLOCK(sc); - - if (startall) - ieee80211_start_all(ic); + } else if (ifp->if_flags & IFF_UP) { + if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) { + bwn_init(sc); + startall = 1; + } + } else + bwn_stop(sc, 1); + 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 -bwn_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +bwn_start(struct ifnet *ifp) { - struct bwn_softc *sc = ic->ic_softc; - int error; + struct bwn_softc *sc = ifp->if_softc; BWN_LOCK(sc); - if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) { - BWN_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - BWN_UNLOCK(sc); - return (error); - } - bwn_start(sc); + bwn_start_locked(ifp); BWN_UNLOCK(sc); - return (0); } static void -bwn_start(struct bwn_softc *sc) +bwn_start_locked(struct ifnet *ifp) { + struct bwn_softc *sc = ifp->if_softc; struct bwn_mac *mac = sc->sc_curmac; struct ieee80211_frame *wh; struct ieee80211_node *ni; @@ -1254,40 +1298,44 @@ bwn_start(struct bwn_softc *sc) BWN_ASSERT_LOCKED(sc); - if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 || mac == NULL || + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL || mac->mac_status < BWN_MAC_STATUS_STARTED) return; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ + if (m == NULL) + break; + if (bwn_tx_isfull(sc, m)) break; ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; if (ni == NULL) { device_printf(sc->sc_dev, "unexpected NULL ni\n"); m_freem(m); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } + KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__)); wh = mtod(m, struct ieee80211_frame *); if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m); if (k == NULL) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } } wh = NULL; /* Catch any invalid use */ + if (bwn_tx_start(sc, ni, m) != 0) { - if (ni != NULL) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if (ni != NULL) ieee80211_free_node(ni); - } + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } + sc->sc_watchdog_timer = 5; } } @@ -1298,6 +1346,7 @@ bwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m) struct bwn_dma_ring *dr; struct bwn_mac *mac = sc->sc_curmac; struct bwn_pio_txqueue *tq; + struct ifnet *ifp = sc->sc_ifp; int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4); BWN_ASSERT_LOCKED(sc); @@ -1312,12 +1361,15 @@ bwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m) } else { tq = bwn_pio_select(mac, M_WME_GETAC(m)); if (tq->tq_free == 0 || pktlen > tq->tq_size || - pktlen > (tq->tq_size - tq->tq_used)) + pktlen > (tq->tq_size - tq->tq_used)) { + tq->tq_stop = 1; goto full; + } } return (0); full: - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; return (1); } @@ -1444,6 +1496,7 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m) struct bwn_dmadesc_generic *desc; struct bwn_dmadesc_meta *mt; struct bwn_softc *sc = mac->mac_sc; + struct ifnet *ifp = sc->sc_ifp; uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache; int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot }; @@ -1466,7 +1519,7 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m) BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr, &mt->mt_paddr, BUS_DMA_NOWAIT); if (error) { - device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n", + if_printf(ifp, "%s: can't load TX buffer (1) %d\n", __func__, error); goto fail; } @@ -1486,7 +1539,7 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m) error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT); if (error && error != EFBIG) { - device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n", + if_printf(ifp, "%s: can't load TX buffer (1) %d\n", __func__, error); goto fail; } @@ -1495,8 +1548,7 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m) m_new = m_defrag(m, M_NOWAIT); if (m_new == NULL) { - device_printf(sc->sc_dev, - "%s: can't defrag TX buffer\n", + if_printf(ifp, "%s: can't defrag TX buffer\n", __func__); error = ENOBUFS; goto fail; @@ -1508,8 +1560,7 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m) error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT); if (error) { - device_printf(sc->sc_dev, - "%s: can't load TX buffer (2) %d\n", + if_printf(ifp, "%s: can't load TX buffer (2) %d\n", __func__, error); goto fail; } @@ -1534,10 +1585,11 @@ static void bwn_watchdog(void *arg) { struct bwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } callout_schedule(&sc->sc_watchdog_ch, hz); } @@ -1808,7 +1860,8 @@ static int bwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; memset(ic->ic_channels, 0, sizeof(ic->ic_channels)); ic->ic_nchans = 0; @@ -2682,10 +2735,11 @@ bwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct bwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct bwn_softc *sc = ifp->if_softc; struct bwn_mac *mac = sc->sc_curmac; - if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 || + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac->mac_status < BWN_MAC_STATUS_STARTED) { ieee80211_free_node(ni); m_freem(m); @@ -2696,6 +2750,7 @@ bwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if (bwn_tx_isfull(sc, m)) { ieee80211_free_node(ni); m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); BWN_UNLOCK(sc); return (ENOBUFS); } @@ -2703,6 +2758,7 @@ bwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if (bwn_tx_start(sc, ni, m) != 0) { if (ni != NULL) ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } sc->sc_watchdog_timer = 5; BWN_UNLOCK(sc); @@ -2722,7 +2778,7 @@ bwn_updateslot(struct ieee80211com *ic) struct bwn_mac *mac; BWN_LOCK(sc); - if (sc->sc_flags & BWN_FLAG_RUNNING) { + if (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) { mac = (struct bwn_mac *)sc->sc_curmac; bwn_set_slot_time(mac, (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20); @@ -2746,7 +2802,7 @@ bwn_update_promisc(struct ieee80211com *ic) BWN_LOCK(sc); mac = sc->sc_curmac; if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) { - if (ic->ic_promisc > 0) + if (ic->ic_ifp->if_flags & IFF_PROMISC) sc->sc_filters |= BWN_MACCTL_PROMISC; else sc->sc_filters &= ~BWN_MACCTL_PROMISC; @@ -2761,7 +2817,7 @@ bwn_update_promisc(struct ieee80211com *ic) static int bwn_wme_update(struct ieee80211com *ic) { - struct bwn_softc *sc = ic->ic_softc; + struct bwn_softc *sc = ic->ic_ifp->if_softc; struct bwn_mac *mac = sc->sc_curmac; struct wmeParams *wmep; int i; @@ -2783,7 +2839,8 @@ bwn_wme_update(struct ieee80211com *ic) static void bwn_scan_start(struct ieee80211com *ic) { - struct bwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct bwn_softc *sc = ifp->if_softc; struct bwn_mac *mac; BWN_LOCK(sc); @@ -2800,7 +2857,8 @@ bwn_scan_start(struct ieee80211com *ic) static void bwn_scan_end(struct ieee80211com *ic) { - struct bwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct bwn_softc *sc = ifp->if_softc; struct bwn_mac *mac; BWN_LOCK(sc); @@ -2816,7 +2874,8 @@ bwn_scan_end(struct ieee80211com *ic) static void bwn_set_channel(struct ieee80211com *ic) { - struct bwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct bwn_softc *sc = ifp->if_softc; struct bwn_mac *mac = sc->sc_curmac; struct bwn_phy *phy = &mac->mac_phy; int chan, error; @@ -2872,11 +2931,15 @@ static struct ieee80211vap * bwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t mac[IEEE80211_ADDR_LEN]) + const uint8_t mac0[IEEE80211_ADDR_LEN]) { + struct ifnet *ifp = ic->ic_ifp; + struct bwn_softc *sc = ifp->if_softc; struct ieee80211vap *vap; struct bwn_vap *bvp; + uint8_t mac[IEEE80211_ADDR_LEN]; + IEEE80211_ADDR_COPY(mac, mac0); switch (opmode) { case IEEE80211_M_HOSTAP: case IEEE80211_M_MBSS: @@ -2890,9 +2953,17 @@ bwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, return (NULL); } - bvp = malloc(sizeof(struct bwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); + IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0); + + bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (bvp == NULL) { + device_printf(sc->sc_dev, "failed to allocate a buffer\n"); + return (NULL); + } vap = &bvp->bv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); + IEEE80211_ADDR_COPY(vap->iv_myaddr, mac); /* override with driver methods */ bvp->bv_newstate = vap->iv_newstate; vap->iv_newstate = bwn_newstate; @@ -2904,7 +2975,7 @@ bwn_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); return (vap); } @@ -2918,10 +2989,30 @@ bwn_vap_delete(struct ieee80211vap *vap) free(bvp, M_80211_VAP); } +static void +bwn_init(void *arg) +{ + struct bwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + int error = 0; + + DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n", + __func__, ifp->if_flags); + + BWN_LOCK(sc); + error = bwn_init_locked(sc); + BWN_UNLOCK(sc); + + if (error == 0) + ieee80211_start_all(ic); /* start all vap's */ +} + static int -bwn_init(struct bwn_softc *sc) +bwn_init_locked(struct bwn_softc *sc) { struct bwn_mac *mac; + struct ifnet *ifp = sc->sc_ifp; int error; BWN_ASSERT_LOCKED(sc); @@ -2947,7 +3038,7 @@ bwn_init(struct bwn_softc *sc) bwn_spu_setdelay(mac, 0); bwn_set_macaddr(mac); - sc->sc_flags |= BWN_FLAG_RUNNING; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc); callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc); @@ -2955,9 +3046,19 @@ bwn_init(struct bwn_softc *sc) } static void -bwn_stop(struct bwn_softc *sc) +bwn_stop(struct bwn_softc *sc, int statechg) +{ + + BWN_LOCK(sc); + bwn_stop_locked(sc, statechg); + BWN_UNLOCK(sc); +} + +static void +bwn_stop_locked(struct bwn_softc *sc, int statechg) { struct bwn_mac *mac = sc->sc_curmac; + struct ifnet *ifp = sc->sc_ifp; BWN_ASSERT_LOCKED(sc); @@ -2976,7 +3077,7 @@ bwn_stop(struct bwn_softc *sc) bwn_core_exit(mac); sc->sc_rf_enabled = 0; - sc->sc_flags &= ~BWN_FLAG_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } static void @@ -4340,7 +4441,7 @@ static void bwn_spu_setdelay(struct bwn_mac *mac, int idle) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint16_t delay; /* microsec */ delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050; @@ -4378,8 +4479,7 @@ bwn_set_macaddr(struct bwn_mac *mac) { bwn_mac_write_bssid(mac); - bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, - mac->mac_sc->sc_ic.ic_macaddr); + bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr); } static void @@ -4549,7 +4649,8 @@ static void bwn_set_opmode(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t ctl; uint16_t cfp_pretbtt; @@ -7842,7 +7943,8 @@ bwn_switch_channel(struct bwn_mac *mac, int chan) { struct bwn_phy *phy = &(mac->mac_phy); struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t channelcookie, savedcookie; int error; @@ -7953,7 +8055,7 @@ bwn_mac_write_bssid(struct bwn_mac *mac) uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2]; bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid); - memcpy(mac_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN); + memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN); memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid, IEEE80211_ADDR_LEN); @@ -8227,8 +8329,9 @@ bwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct bwn_vap *bvp = BWN_VAP(vap); struct ieee80211com *ic= vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; enum ieee80211_state ostate = vap->iv_state; - struct bwn_softc *sc = ic->ic_softc; + struct bwn_softc *sc = ifp->if_softc; struct bwn_mac *mac = sc->sc_curmac; int error; @@ -8267,6 +8370,7 @@ bwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) /* XXX nothing to do? */ } else if (nstate == IEEE80211_S_RUN) { memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN); + memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN); bwn_set_opmode(mac); bwn_set_pretbtt(mac); bwn_spu_setdelay(mac, 0); @@ -8282,7 +8386,7 @@ static void bwn_set_pretbtt(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint16_t pretbtt; if (ic->ic_opmode == IEEE80211_M_IBSS) @@ -8340,6 +8444,7 @@ bwn_intrtask(void *arg, int npending) { struct bwn_mac *mac = arg; struct bwn_softc *sc = mac->mac_sc; + struct ifnet *ifp = sc->sc_ifp; uint32_t merged = 0; int i, tx = 0, rx = 0; @@ -8439,8 +8544,10 @@ bwn_intrtask(void *arg, int npending) bwn_led_event(mac, evt); } - if (mbufq_first(&sc->sc_snd) != NULL) - bwn_start(sc); + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { + if (!IFQ_IS_EMPTY(&ifp->if_snd)) + bwn_start_locked(ifp); + } BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ); BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE); @@ -8452,7 +8559,8 @@ static void bwn_restart(struct bwn_mac *mac, const char *msg) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; if (mac->mac_status < BWN_MAC_STATUS_INITED) return; @@ -8497,7 +8605,7 @@ static void bwn_intr_tbtt_indication(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; if (ic->ic_opmode != IEEE80211_M_HOSTAP) bwn_psctl(mac, 0); @@ -8520,7 +8628,7 @@ static void bwn_intr_beacon(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint32_t cmd, beacon0, beacon1; if (ic->ic_opmode == IEEE80211_M_HOSTAP || @@ -8809,6 +8917,7 @@ bwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot) struct bwn_dmadesc_generic *desc; struct bwn_dmadesc_meta *meta; struct bwn_rxhdr4 *rxhdr; + struct ifnet *ifp = sc->sc_ifp; struct mbuf *m; uint32_t macstat; int32_t tmp; @@ -8821,14 +8930,14 @@ bwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot) m = meta->mt_m; if (bwn_dma_newbuf(dr, desc, meta, 0)) { - counter_u64_add(sc->sc_ic.ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } rxhdr = mtod(m, struct bwn_rxhdr4 *); len = le16toh(rxhdr->frame_len); if (len <= 0) { - counter_u64_add(sc->sc_ic.ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } if (bwn_dma_check_redzone(dr, m)) { @@ -8864,6 +8973,7 @@ bwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot) } } + m->m_pkthdr.rcvif = ifp; m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset; m_adj(m, dr->dr_frameoffset); @@ -8950,6 +9060,7 @@ bwn_pio_rxeof(struct bwn_pio_rxqueue *prq) struct bwn_mac *mac = prq->prq_mac; struct bwn_softc *sc = mac->mac_sc; struct bwn_rxhdr4 rxhdr; + struct ifnet *ifp = sc->sc_ifp; struct mbuf *m; uint32_t ctl32, macstat, v32; unsigned int i, padding; @@ -9046,6 +9157,7 @@ ready: } } + m->m_pkthdr.rcvif = ifp; m->m_len = m->m_pkthdr.len = totlen; bwn_rxeof(prq->prq_mac, m, &rxhdr); @@ -9190,7 +9302,8 @@ bwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr) struct bwn_softc *sc = mac->mac_sc; struct ieee80211_frame_min *wh; struct ieee80211_node *ni; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t macstat; int padding, rate, rssi = 0, noise = 0, type; uint16_t phytype, phystat0, phystat3, chanstat; @@ -9254,6 +9367,8 @@ bwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr) rssi = rxhdr->phy.abg.rssi; /* XXX incorrect RSSI calculation? */ noise = mac->mac_stats.link_noise; + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + BWN_UNLOCK(sc); ni = ieee80211_find_rxnode(ic, wh); @@ -9278,6 +9393,9 @@ bwn_dma_handle_txeof(struct bwn_mac *mac, struct bwn_dmadesc_generic *desc; struct bwn_dmadesc_meta *meta; struct bwn_softc *sc = mac->mac_sc; + struct ieee80211_node *ni; + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; int slot; BWN_ASSERT_LOCKED(sc); @@ -9303,22 +9421,37 @@ bwn_dma_handle_txeof(struct bwn_mac *mac, KASSERT(meta->mt_m != NULL, ("%s:%d: fail", __func__, __LINE__)); - ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0); - meta->mt_ni = NULL; + ni = meta->mt_ni; + m = meta->mt_m; + if (ni != NULL) { + /* + * Do any tx complete callback. Note this must + * be done before releasing the node reference. + */ + if (m->m_flags & M_TXCB) + ieee80211_process_callback(ni, m, 0); + ieee80211_free_node(ni); + meta->mt_ni = NULL; + } + m_freem(m); meta->mt_m = NULL; - } else + } else { KASSERT(meta->mt_m == NULL, ("%s:%d: fail", __func__, __LINE__)); + } dr->dr_usedslot--; - if (meta->mt_islast) + if (meta->mt_islast) { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); break; + } slot = bwn_dma_nextslot(dr, slot); } sc->sc_watchdog_timer = 0; if (dr->dr_stop) { KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME, ("%s:%d: fail", __func__, __LINE__)); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; dr->dr_stop = 0; } } @@ -9330,6 +9463,7 @@ bwn_pio_handle_txeof(struct bwn_mac *mac, struct bwn_pio_txqueue *tq; struct bwn_pio_txpkt *tp = NULL; struct bwn_softc *sc = mac->mac_sc; + struct ifnet *ifp = sc->sc_ifp; BWN_ASSERT_LOCKED(sc); @@ -9354,7 +9488,13 @@ bwn_pio_handle_txeof(struct bwn_mac *mac, tp->tp_m = NULL; TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + sc->sc_watchdog_timer = 0; + if (tq->tq_stop) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + tq->tq_stop = 0; + } } static void @@ -9362,7 +9502,8 @@ bwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags) { struct bwn_softc *sc = mac->mac_sc; struct bwn_phy *phy = &mac->mac_phy; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; unsigned long now; int result; @@ -9466,7 +9607,8 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni, struct ieee80211_frame_rts *rts; const struct ieee80211_txparam *tp; struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mbuf *mprot; unsigned int len; uint32_t macctl = 0; @@ -9964,7 +10106,7 @@ static void bwn_phy_lock(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; KASSERT(siba_get_revid(sc->sc_dev) >= 3, ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev))); @@ -9977,7 +10119,7 @@ static void bwn_phy_unlock(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; KASSERT(siba_get_revid(sc->sc_dev) >= 3, ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev))); @@ -10493,7 +10635,8 @@ static void bwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t val; int i; @@ -10502,7 +10645,7 @@ bwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate) sc->sc_led_blinking = 0; } - if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; val = BWN_READ_2(mac, BWN_GPIO_CONTROL); @@ -10637,9 +10780,7 @@ bwn_suspend(device_t dev) { struct bwn_softc *sc = device_get_softc(dev); - BWN_LOCK(sc); - bwn_stop(sc); - BWN_UNLOCK(sc); + bwn_stop(sc, 1); return (0); } @@ -10647,14 +10788,10 @@ static int bwn_resume(device_t dev) { struct bwn_softc *sc = device_get_softc(dev); - int error = EDOOFUS; + struct ifnet *ifp = sc->sc_ifp; - BWN_LOCK(sc); - if (sc->sc_ic.ic_nrunning > 0) - error = bwn_init(sc); - BWN_UNLOCK(sc); - if (error == 0) - ieee80211_start_all(&sc->sc_ic); + if (ifp->if_flags & IFF_UP) + bwn_init(sc); return (0); } @@ -10733,7 +10870,8 @@ bwn_phy_lp_init(struct bwn_mac *mac) struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; const struct bwn_stxtable *st; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int i, error; uint16_t tmp; @@ -10886,7 +11024,8 @@ static uint32_t bwn_phy_lp_get_default_chan(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36); } @@ -10919,7 +11058,8 @@ bwn_phy_lp_readsprom(struct bwn_mac *mac) { struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { plp->plp_txisoband_m = siba_sprom_get_tri2g(sc->sc_dev); @@ -10958,7 +11098,8 @@ bwn_phy_lp_txpctl_init(struct bwn_mac *mac) struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 }; struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 }; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; bwn_phy_lp_set_txgain(mac, IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz); @@ -10970,7 +11111,8 @@ bwn_phy_lp_calib(struct bwn_mac *mac) { struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct bwn_rxcompco *rc = NULL; struct bwn_txgain ogain; int i, omode, oafeovr, orf, obbmult; @@ -11316,7 +11458,8 @@ bwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq) { struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t iso, tmp[3]; KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__)); @@ -11587,7 +11730,8 @@ bwn_phy_lp_bbinit_r2(struct bwn_mac *mac) { struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static const struct bwn_wpair v1[] = { { BWN_PHY_AFE_DAC_CTL, 0x50 }, { BWN_PHY_AFE_CTL, 0x8800 }, @@ -11697,7 +11841,8 @@ bwn_phy_lp_bbinit_r01(struct bwn_mac *mac) { struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static const struct bwn_smpair v1[] = { { BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 }, { BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 }, @@ -11882,7 +12027,8 @@ bwn_phy_lp_b2062_init(struct bwn_mac *mac) ((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff) struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static const struct bwn_b2062_freq freqdata_tab[] = { { 12000, { 6, 6, 6, 6, 10, 6 } }, { 13000, { 4, 4, 4, 4, 11, 7 } }, @@ -12228,7 +12374,8 @@ bwn_phy_lp_b2062_tblinit(struct bwn_mac *mac) #define FLAG_A 0x01 #define FLAG_G 0x02 struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = { { BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, }, { BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, }, @@ -12301,7 +12448,8 @@ bwn_phy_lp_b2063_tblinit(struct bwn_mac *mac) #define FLAG_A 0x01 #define FLAG_G 0x02 struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = { { BWN_B2063_COM1, 0x0, 0x0, FLAG_G, }, { BWN_B2063_COM10, 0x1, 0x0, FLAG_A, }, @@ -12519,7 +12667,8 @@ static void bwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp; if (mac->mac_phy.rev < 2) { @@ -12587,7 +12736,8 @@ bwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user) { struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp; struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; if (user) plp->plp_crsusr_off = 0; @@ -13130,7 +13280,8 @@ static void bwn_phy_lp_tblinit_txgain(struct bwn_mac *mac) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; static struct bwn_txgain_entry txgain_r2[] = { { 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 }, { 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 }, @@ -14007,7 +14158,8 @@ bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset, struct bwn_txgain_entry te) { struct bwn_softc *sc = mac->mac_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__)); diff --git a/sys/dev/bwn/if_bwnvar.h b/sys/dev/bwn/if_bwnvar.h index b8295ec..f6647b0 100644 --- a/sys/dev/bwn/if_bwnvar.h +++ b/sys/dev/bwn/if_bwnvar.h @@ -656,6 +656,7 @@ struct bwn_pio_txqueue { uint16_t tq_size; uint16_t tq_used; uint16_t tq_free; + uint8_t tq_stop; uint8_t tq_index; struct bwn_pio_txpkt tq_pkts[BWN_PIO_MAX_TXPACKETS]; TAILQ_HEAD(, bwn_pio_txpkt) tq_pktlist; @@ -896,18 +897,17 @@ struct bwn_vap { struct bwn_softc { device_t sc_dev; struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; unsigned sc_flags; #define BWN_FLAG_ATTACHED (1 << 0) #define BWN_FLAG_INVALID (1 << 1) #define BWN_FLAG_NEED_BEACON_TP (1 << 2) -#define BWN_FLAG_RUNNING (1 << 3) unsigned sc_debug; struct bwn_mac *sc_curmac; TAILQ_HEAD(, bwn_mac) sc_maclist; + uint8_t sc_macaddr[IEEE80211_ADDR_LEN]; uint8_t sc_bssid[IEEE80211_ADDR_LEN]; unsigned int sc_filters; uint8_t sc_beacons[2]; diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index c30f31c..9c57aed 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/sysctl.h> #include <sys/kthread.h> -#include <sys/limits.h> #include <net/if.h> #include <net/if_var.h> @@ -167,6 +166,7 @@ static void ndis_starttask (device_object *, void *); static void ndis_resettask (device_object *, void *); static void ndis_inputtask (device_object *, void *); static int ndis_ioctl (struct ifnet *, u_long, caddr_t); +static int ndis_ioctl_80211 (struct ifnet *, u_long, caddr_t); static int ndis_newstate (struct ieee80211vap *, enum ieee80211_state, int); static int ndis_nettype_chan (uint32_t); @@ -197,15 +197,10 @@ static int ndis_add_key (struct ieee80211vap *, const struct ieee80211_key *, const u_int8_t []); static int ndis_del_key (struct ieee80211vap *, const struct ieee80211_key *); + static void ndis_setmulti (struct ndis_softc *); static void ndis_map_sclist (void *, bus_dma_segment_t *, int, bus_size_t, int); -static int ndis_ifattach(struct ndis_softc *); - -static int ndis_80211attach(struct ndis_softc *); -static int ndis_80211ioctl(struct ieee80211com *, u_long , void *); -static int ndis_80211transmit(struct ieee80211com *, struct mbuf *); -static void ndis_80211parent(struct ieee80211com *); static int ndisdrv_loaded = 0; @@ -541,12 +536,16 @@ ndis_nettype_mode(uint32_t type) * setup and ethernet/BPF attach. */ int -ndis_attach(device_t dev) +ndis_attach(dev) + device_t dev; { + u_char eaddr[ETHER_ADDR_LEN]; struct ndis_softc *sc; driver_object *pdrv; device_object *pdo; - int error = 0, len; + struct ifnet *ifp = NULL; + int error = 0, len, mode; + uint8_t bands = 0; int i; sc = device_get_softc(dev); @@ -560,7 +559,6 @@ ndis_attach(device_t dev) InitializeListHead(&sc->ndisusb_tasklist); InitializeListHead(&sc->ndisusb_xferdonelist); callout_init(&sc->ndis_stat_callout, 1); - mbufq_init(&sc->ndis_rxqueue, INT_MAX); /* XXXGL: sane maximum */ if (sc->ndis_iftype == PCMCIABus) { error = ndis_alloc_amem(sc); @@ -637,8 +635,15 @@ ndis_attach(device_t dev) } /* + * Get station address from the driver. + */ + len = sizeof(eaddr); + ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len); + + /* * Figure out how big to make the TX buffer pool. */ + len = sizeof(sc->ndis_maxpkts); if (ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS, &sc->ndis_maxpkts, &len)) { @@ -691,89 +696,95 @@ ndis_attach(device_t dev) */ for (i = 0; i < sc->ndis_oidcnt; i++) if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) { - sc->ndis_80211 = 1; + sc->ndis_80211++; break; } if (sc->ndis_80211) - error = ndis_80211attach(sc); + ifp = if_alloc(IFT_IEEE80211); else - error = ndis_ifattach(sc); - -fail: - if (error) { - ndis_detach(dev); - return (error); + ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + error = ENOSPC; + goto fail; } + sc->ifp = ifp; + ifp->if_softc = sc; - if (sc->ndis_iftype == PNPBus && ndisusb_halt == 0) - return (error); - - DPRINTF(("attach done.\n")); - /* We're done talking to the NIC for now; halt it. */ - ndis_halt_nic(sc); - DPRINTF(("halting done.\n")); - - return (error); -} + /* Check for task offload support. */ + ndis_probe_offload(sc); -static int -ndis_80211attach(struct ndis_softc *sc) -{ - struct ieee80211com *ic = &sc->ndis_ic; - ndis_80211_rates_ex rates; - struct ndis_80211_nettype_list *ntl; - uint32_t arg; - int mode, i, r, len; - uint8_t bands = 0; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = ndis_ioctl; + ifp->if_start = ndis_start; + ifp->if_init = ndis_init; + ifp->if_baudrate = 10000000; + IFQ_SET_MAXLEN(&ifp->if_snd, 50); + ifp->if_snd.ifq_drv_maxlen = 25; + IFQ_SET_READY(&ifp->if_snd); + ifp->if_capenable = ifp->if_capabilities; + ifp->if_hwassist = sc->ndis_hwassist; - callout_init(&sc->ndis_scan_callout, 1); + /* Do media setup */ + if (sc->ndis_80211) { + struct ieee80211com *ic = ifp->if_l2com; + ndis_80211_rates_ex rates; + struct ndis_80211_nettype_list *ntl; + uint32_t arg; + int r; + + callout_init(&sc->ndis_scan_callout, 1); + + ifp->if_ioctl = ndis_ioctl_80211; + ic->ic_ifp = ifp; + ic->ic_softc = sc; + ic->ic_name = device_get_nameunit(dev); + ic->ic_opmode = IEEE80211_M_STA; + ic->ic_phytype = IEEE80211_T_DS; + ic->ic_caps = IEEE80211_C_8023ENCAP | + IEEE80211_C_STA | IEEE80211_C_IBSS; + setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); + len = 0; + r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, + NULL, &len); + if (r != ENOSPC) + goto nonettypes; + ntl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); + r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, + ntl, &len); + if (r != 0) { + free(ntl, M_DEVBUF); + goto nonettypes; + } - ic->ic_softc = sc; - ic->ic_ioctl = ndis_80211ioctl; - ic->ic_name = device_get_nameunit(sc->ndis_dev); - ic->ic_opmode = IEEE80211_M_STA; - ic->ic_phytype = IEEE80211_T_DS; - ic->ic_caps = IEEE80211_C_8023ENCAP | - IEEE80211_C_STA | IEEE80211_C_IBSS; - setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); - len = 0; - r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, NULL, &len); - if (r != ENOSPC) - goto nonettypes; - ntl = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, ntl, &len); - if (r != 0) { + for (i = 0; i < ntl->ntl_items; i++) { + mode = ndis_nettype_mode(ntl->ntl_type[i]); + if (mode) { + setbit(ic->ic_modecaps, mode); + setbit(&bands, mode); + } else + device_printf(dev, "Unknown nettype %d\n", + ntl->ntl_type[i]); + } free(ntl, M_DEVBUF); - goto nonettypes; - } - - for (i = 0; i < ntl->ntl_items; i++) { - mode = ndis_nettype_mode(ntl->ntl_type[i]); - if (mode) { - setbit(ic->ic_modecaps, mode); - setbit(&bands, mode); - } else - device_printf(sc->ndis_dev, "Unknown nettype %d\n", - ntl->ntl_type[i]); - } - free(ntl, M_DEVBUF); nonettypes: - /* Default to 11b channels if the card did not supply any */ - if (bands == 0) { - setbit(ic->ic_modecaps, IEEE80211_MODE_11B); - setbit(&bands, IEEE80211_MODE_11B); - } - len = sizeof(rates); - bzero((char *)&rates, len); - r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, (void *)rates, &len); - if (r != 0) - device_printf(sc->ndis_dev, "get rates failed: 0x%x\n", r); - /* - * Since the supported rates only up to 8 can be supported, - * if this is not 802.11b we're just going to be faking it - * all up to heck. - */ + /* Default to 11b channels if the card did not supply any */ + if (bands == 0) { + setbit(ic->ic_modecaps, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11B); + } + len = sizeof(rates); + bzero((char *)&rates, len); + r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, + (void *)rates, &len); + if (r) + device_printf(dev, "get rates failed: 0x%x\n", r); + /* + * Since the supported rates only up to 8 can be supported, + * if this is not 802.11b we're just going to be faking it + * all up to heck. + */ #define TESTSETRATE(x, y) \ do { \ @@ -793,198 +804,174 @@ nonettypes: #define INCRATE(x) \ ic->ic_sup_rates[x].rs_nrates++ - ic->ic_curmode = IEEE80211_MODE_AUTO; - if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) - ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0; - if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) - ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0; - if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) - ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0; - for (i = 0; i < len; i++) { - switch (rates[i] & IEEE80211_RATE_VAL) { - case 2: - case 4: - case 11: - case 10: - case 22: - if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) { - /* Lazy-init 802.11b. */ - setbit(ic->ic_modecaps, IEEE80211_MODE_11B); - ic->ic_sup_rates[IEEE80211_MODE_11B]. - rs_nrates = 0; - } - SETRATE(IEEE80211_MODE_11B, rates[i]); - INCRATE(IEEE80211_MODE_11B); - break; - default: - if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { - SETRATE(IEEE80211_MODE_11A, rates[i]); - INCRATE(IEEE80211_MODE_11A); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { - SETRATE(IEEE80211_MODE_11G, rates[i]); - INCRATE(IEEE80211_MODE_11G); + ic->ic_curmode = IEEE80211_MODE_AUTO; + if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) + ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0; + if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) + ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0; + if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) + ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0; + for (i = 0; i < len; i++) { + switch (rates[i] & IEEE80211_RATE_VAL) { + case 2: + case 4: + case 11: + case 10: + case 22: + if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) { + /* Lazy-init 802.11b. */ + setbit(ic->ic_modecaps, + IEEE80211_MODE_11B); + ic->ic_sup_rates[IEEE80211_MODE_11B]. + rs_nrates = 0; + } + SETRATE(IEEE80211_MODE_11B, rates[i]); + INCRATE(IEEE80211_MODE_11B); + break; + default: + if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { + SETRATE(IEEE80211_MODE_11A, rates[i]); + INCRATE(IEEE80211_MODE_11A); + } + if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { + SETRATE(IEEE80211_MODE_11G, rates[i]); + INCRATE(IEEE80211_MODE_11G); + } + break; } - break; } - } - - /* - * If the hardware supports 802.11g, it most - * likely supports 802.11b and all of the - * 802.11b and 802.11g speeds, so maybe we can - * just cheat here. Just how in the heck do - * we detect turbo modes, though? - */ - if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) { - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|2); - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|4); - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|11); - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|22); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { - TESTSETRATE(IEEE80211_MODE_11G, 48); - TESTSETRATE(IEEE80211_MODE_11G, 72); - TESTSETRATE(IEEE80211_MODE_11G, 96); - TESTSETRATE(IEEE80211_MODE_11G, 108); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { - TESTSETRATE(IEEE80211_MODE_11A, 48); - TESTSETRATE(IEEE80211_MODE_11A, 72); - TESTSETRATE(IEEE80211_MODE_11A, 96); - TESTSETRATE(IEEE80211_MODE_11A, 108); - } + /* + * If the hardware supports 802.11g, it most + * likely supports 802.11b and all of the + * 802.11b and 802.11g speeds, so maybe we can + * just cheat here. Just how in the heck do + * we detect turbo modes, though? + */ + if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) { + TESTSETRATE(IEEE80211_MODE_11B, + IEEE80211_RATE_BASIC|2); + TESTSETRATE(IEEE80211_MODE_11B, + IEEE80211_RATE_BASIC|4); + TESTSETRATE(IEEE80211_MODE_11B, + IEEE80211_RATE_BASIC|11); + TESTSETRATE(IEEE80211_MODE_11B, + IEEE80211_RATE_BASIC|22); + } + if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { + TESTSETRATE(IEEE80211_MODE_11G, 48); + TESTSETRATE(IEEE80211_MODE_11G, 72); + TESTSETRATE(IEEE80211_MODE_11G, 96); + TESTSETRATE(IEEE80211_MODE_11G, 108); + } + if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { + TESTSETRATE(IEEE80211_MODE_11A, 48); + TESTSETRATE(IEEE80211_MODE_11A, 72); + TESTSETRATE(IEEE80211_MODE_11A, 96); + TESTSETRATE(IEEE80211_MODE_11A, 108); + } #undef SETRATE #undef INCRATE -#undef TESTSETRATE + ieee80211_init_channels(ic, NULL, &bands); - ieee80211_init_channels(ic, NULL, &bands); - - /* - * To test for WPA support, we need to see if we can - * set AUTHENTICATION_MODE to WPA and read it back - * successfully. - */ - i = sizeof(arg); - arg = NDIS_80211_AUTHMODE_WPA; - r = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i); - if (r == 0) { - r = ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i); - if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA) - ic->ic_caps |= IEEE80211_C_WPA; - } + /* + * To test for WPA support, we need to see if we can + * set AUTHENTICATION_MODE to WPA and read it back + * successfully. + */ + i = sizeof(arg); + arg = NDIS_80211_AUTHMODE_WPA; + r = ndis_set_info(sc, + OID_802_11_AUTHENTICATION_MODE, &arg, &i); + if (r == 0) { + r = ndis_get_info(sc, + OID_802_11_AUTHENTICATION_MODE, &arg, &i); + if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA) + ic->ic_caps |= IEEE80211_C_WPA; + } - /* - * To test for supported ciphers, we set each - * available encryption type in descending order. - * If ENC3 works, then we have WEP, TKIP and AES. - * If only ENC2 works, then we have WEP and TKIP. - * If only ENC1 works, then we have just WEP. - */ - i = sizeof(arg); - arg = NDIS_80211_WEPSTAT_ENC3ENABLED; - r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); - if (r == 0) { - ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP - | IEEE80211_CRYPTO_TKIP - | IEEE80211_CRYPTO_AES_CCM; - goto got_crypto; - } - arg = NDIS_80211_WEPSTAT_ENC2ENABLED; - r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); - if (r == 0) { - ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP - | IEEE80211_CRYPTO_TKIP; - goto got_crypto; - } - arg = NDIS_80211_WEPSTAT_ENC1ENABLED; - r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); - if (r == 0) - ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP; + /* + * To test for supported ciphers, we set each + * available encryption type in descending order. + * If ENC3 works, then we have WEP, TKIP and AES. + * If only ENC2 works, then we have WEP and TKIP. + * If only ENC1 works, then we have just WEP. + */ + i = sizeof(arg); + arg = NDIS_80211_WEPSTAT_ENC3ENABLED; + r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); + if (r == 0) { + ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP + | IEEE80211_CRYPTO_TKIP + | IEEE80211_CRYPTO_AES_CCM; + goto got_crypto; + } + arg = NDIS_80211_WEPSTAT_ENC2ENABLED; + r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); + if (r == 0) { + ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP + | IEEE80211_CRYPTO_TKIP; + goto got_crypto; + } + arg = NDIS_80211_WEPSTAT_ENC1ENABLED; + r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); + if (r == 0) + ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP; got_crypto: - i = sizeof(arg); - r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i); - if (r == 0) - ic->ic_caps |= IEEE80211_C_PMGT; - - r = ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &i); - if (r == 0) - ic->ic_caps |= IEEE80211_C_TXPMGT; - - /* - * Get station address from the driver. - */ - len = sizeof(ic->ic_macaddr); - ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &ic->ic_macaddr, &len); - - ieee80211_ifattach(ic); - ic->ic_raw_xmit = ndis_raw_xmit; - ic->ic_scan_start = ndis_scan_start; - ic->ic_scan_end = ndis_scan_end; - ic->ic_set_channel = ndis_set_channel; - ic->ic_scan_curchan = ndis_scan_curchan; - ic->ic_scan_mindwell = ndis_scan_mindwell; - ic->ic_bsschan = IEEE80211_CHAN_ANYC; - ic->ic_vap_create = ndis_vap_create; - ic->ic_vap_delete = ndis_vap_delete; - ic->ic_update_mcast = ndis_update_mcast; - ic->ic_update_promisc = ndis_update_promisc; - ic->ic_transmit = ndis_80211transmit; - ic->ic_parent = ndis_80211parent; - - if (bootverbose) - ieee80211_announce(ic); - - return (0); -} - -static int -ndis_ifattach(struct ndis_softc *sc) -{ - struct ifnet *ifp; - u_char eaddr[ETHER_ADDR_LEN]; - int len; - - ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) - return (ENOSPC); - sc->ifp = ifp; - ifp->if_softc = sc; + i = sizeof(arg); + r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i); + if (r == 0) + ic->ic_caps |= IEEE80211_C_PMGT; + + r = ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &i); + if (r == 0) + ic->ic_caps |= IEEE80211_C_TXPMGT; + + ieee80211_ifattach(ic, eaddr); + ic->ic_raw_xmit = ndis_raw_xmit; + ic->ic_scan_start = ndis_scan_start; + ic->ic_scan_end = ndis_scan_end; + ic->ic_set_channel = ndis_set_channel; + ic->ic_scan_curchan = ndis_scan_curchan; + ic->ic_scan_mindwell = ndis_scan_mindwell; + ic->ic_bsschan = IEEE80211_CHAN_ANYC; + //ic->ic_bss->ni_chan = ic->ic_bsschan; + ic->ic_vap_create = ndis_vap_create; + ic->ic_vap_delete = ndis_vap_delete; + ic->ic_update_mcast = ndis_update_mcast; + ic->ic_update_promisc = ndis_update_promisc; + + if (bootverbose) + ieee80211_announce(ic); - /* Check for task offload support. */ - ndis_probe_offload(sc); + } else { + ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, + ndis_ifmedia_sts); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); + ifmedia_add(&sc->ifmedia, + IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); + ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); + ether_ifattach(ifp, eaddr); + } - /* - * Get station address from the driver. - */ - len = sizeof(eaddr); - ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, eaddr, &len); +fail: + if (error) { + ndis_detach(dev); + return (error); + } - if_initname(ifp, device_get_name(sc->ndis_dev), - device_get_unit(sc->ndis_dev)); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = ndis_ioctl; - ifp->if_start = ndis_start; - ifp->if_init = ndis_init; - ifp->if_baudrate = 10000000; - IFQ_SET_MAXLEN(&ifp->if_snd, 50); - ifp->if_snd.ifq_drv_maxlen = 25; - IFQ_SET_READY(&ifp->if_snd); - ifp->if_capenable = ifp->if_capabilities; - ifp->if_hwassist = sc->ndis_hwassist; + if (sc->ndis_iftype == PNPBus && ndisusb_halt == 0) + return (error); - ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, - ndis_ifmedia_sts); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); - ether_ifattach(ifp, eaddr); + DPRINTF(("attach done.\n")); + /* We're done talking to the NIC for now; halt it. */ + ndis_halt_nic(sc); + DPRINTF(("halting done.\n")); - return (0); + return (error); } static struct ieee80211vap * @@ -998,16 +985,18 @@ ndis_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - nvp = malloc(sizeof(struct ndis_vap), M_80211_VAP, M_WAITOK | M_ZERO); + nvp = (struct ndis_vap *) malloc(sizeof(struct ndis_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (nvp == NULL) + return NULL; vap = &nvp->vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override with driver methods */ nvp->newstate = vap->iv_newstate; vap->iv_newstate = ndis_newstate; /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, ndis_media_status, - mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ndis_media_status); ic->ic_opmode = opmode; /* install key handing routines */ vap->iv_key_set = ndis_add_key; @@ -1020,7 +1009,8 @@ ndis_vap_delete(struct ieee80211vap *vap) { struct ndis_vap *nvp = NDIS_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct ndis_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ndis_softc *sc = ifp->if_softc; ndis_stop(sc); callout_drain(&sc->ndis_scan_callout); @@ -1036,27 +1026,28 @@ ndis_vap_delete(struct ieee80211vap *vap) * allocated. */ int -ndis_detach(device_t dev) +ndis_detach(dev) + device_t dev; { - struct ifnet *ifp; struct ndis_softc *sc; + struct ifnet *ifp; driver_object *drv; sc = device_get_softc(dev); NDIS_LOCK(sc); - if (!sc->ndis_80211) - ifp = sc->ifp; - else - ifp = NULL; + ifp = sc->ifp; if (ifp != NULL) ifp->if_flags &= ~IFF_UP; + if (device_is_attached(dev)) { NDIS_UNLOCK(sc); ndis_stop(sc); - if (sc->ndis_80211) - ieee80211_ifdetach(&sc->ndis_ic); - else if (ifp != NULL) - ether_ifdetach(ifp); + if (ifp != NULL) { + if (sc->ndis_80211) + ieee80211_ifdetach(ifp->if_l2com); + else + ether_ifdetach(ifp); + } } else NDIS_UNLOCK(sc); @@ -1311,11 +1302,11 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2) IoFreeMdl(p->np_private.npp_head); NdisFreePacket(p); KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); - mbufq_enqueue(&sc->ndis_rxqueue, m); + _IF_ENQUEUE(&sc->ndis_rxqueue, m); KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); IoQueueWorkItem(sc->ndis_inputitem, (io_workitem_func)ndis_inputtask_wrap, - WORKQUEUE_CRITICAL, sc); + WORKQUEUE_CRITICAL, ifp); } if (status == NDIS_STATUS_FAILURE) @@ -1359,11 +1350,11 @@ ndis_rxeof_xfr_done(adapter, packet, status, len) m->m_len = m->m_pkthdr.len; m->m_pkthdr.rcvif = ifp; KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); - mbufq_enqueue(&sc->ndis_rxqueue, m); + _IF_ENQUEUE(&sc->ndis_rxqueue, m); KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); IoQueueWorkItem(sc->ndis_inputitem, (io_workitem_func)ndis_inputtask_wrap, - WORKQUEUE_CRITICAL, sc); + WORKQUEUE_CRITICAL, ifp); } /* * A frame has been uploaded: pass the resulting mbuf chain up to @@ -1408,7 +1399,7 @@ ndis_rxeof(adapter, packets, pktcnt) * before we're completely ready to handle them. If we detect this, * we need to return them to the miniport and ignore them. */ - if (!sc->ndis_running) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { for (i = 0; i < pktcnt; i++) { p = packets[i]; if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) { @@ -1482,11 +1473,11 @@ ndis_rxeof(adapter, packets, pktcnt) } KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); - mbufq_enqueue(&sc->ndis_rxqueue, m0); + _IF_ENQUEUE(&sc->ndis_rxqueue, m0); KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); IoQueueWorkItem(sc->ndis_inputitem, (io_workitem_func)ndis_inputtask_wrap, - WORKQUEUE_CRITICAL, sc); + WORKQUEUE_CRITICAL, ifp); } } } @@ -1498,29 +1489,34 @@ ndis_rxeof(adapter, packets, pktcnt) * 'dispatch level' per-cpu sleep lock). */ static void -ndis_inputtask(device_object *dobj, void *arg) +ndis_inputtask(dobj, arg) + device_object *dobj; + void *arg; { ndis_miniport_block *block; - struct ndis_softc *sc = arg; + struct ifnet *ifp; + struct ndis_softc *sc; struct mbuf *m; + struct ieee80211com *ic; + struct ieee80211vap *vap; uint8_t irql; + ifp = arg; + sc = ifp->if_softc; + ic = ifp->if_l2com; + vap = TAILQ_FIRST(&ic->ic_vaps); block = dobj->do_devext; KeAcquireSpinLock(&sc->ndis_rxlock, &irql); - while ((m = mbufq_dequeue(&sc->ndis_rxqueue)) != NULL) { + while(1) { + _IF_DEQUEUE(&sc->ndis_rxqueue, m); + if (m == NULL) + break; KeReleaseSpinLock(&sc->ndis_rxlock, irql); - if ((sc->ndis_80211 != 0)) { - struct ieee80211com *ic = &sc->ndis_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - if (vap != NULL) - vap->iv_deliver_data(vap, vap->iv_bss, m); - } else { - struct ifnet *ifp = sc->ifp; - + if ((sc->ndis_80211 != 0) && (vap != NULL)) + vap->iv_deliver_data(vap, vap->iv_bss, m); + else (*ifp->if_input)(ifp, m); - } KeAcquireSpinLock(&sc->ndis_rxlock, &irql); } KeReleaseSpinLock(&sc->ndis_rxlock, irql); @@ -1680,12 +1676,20 @@ ndis_tick(xsc) } static void -ndis_ticktask(device_object *d, void *xsc) +ndis_ticktask(d, xsc) + device_object *d; + void *xsc; { - struct ndis_softc *sc = xsc; + struct ndis_softc *sc; + struct ieee80211com *ic; + struct ieee80211vap *vap; ndis_checkforhang_handler hangfunc; uint8_t rval; + sc = xsc; + ic = sc->ifp->if_l2com; + vap = TAILQ_FIRST(&ic->ic_vaps); + NDIS_LOCK(sc); if (!NDIS_INITIALIZED(sc)) { NDIS_UNLOCK(sc); @@ -1708,18 +1712,12 @@ ndis_ticktask(device_object *d, void *xsc) if (sc->ndis_link == 0 && sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) { sc->ndis_link = 1; - if (sc->ndis_80211 != 0) { - struct ieee80211com *ic = &sc->ndis_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - if (vap != NULL) { - NDIS_UNLOCK(sc); - ndis_getstate_80211(sc); - ieee80211_new_state(vap, IEEE80211_S_RUN, -1); - NDIS_LOCK(sc); - if_link_state_change(vap->iv_ifp, - LINK_STATE_UP); - } + if ((sc->ndis_80211 != 0) && (vap != NULL)) { + NDIS_UNLOCK(sc); + ndis_getstate_80211(sc); + ieee80211_new_state(vap, IEEE80211_S_RUN, -1); + NDIS_LOCK(sc); + if_link_state_change(vap->iv_ifp, LINK_STATE_UP); } else if_link_state_change(sc->ifp, LINK_STATE_UP); } @@ -1727,17 +1725,11 @@ ndis_ticktask(device_object *d, void *xsc) if (sc->ndis_link == 1 && sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) { sc->ndis_link = 0; - if (sc->ndis_80211 != 0) { - struct ieee80211com *ic = &sc->ndis_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - if (vap != NULL) { - NDIS_UNLOCK(sc); - ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); - NDIS_LOCK(sc); - if_link_state_change(vap->iv_ifp, - LINK_STATE_DOWN); - } + if ((sc->ndis_80211 != 0) && (vap != NULL)) { + NDIS_UNLOCK(sc); + ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); + NDIS_LOCK(sc); + if_link_state_change(vap->iv_ifp, LINK_STATE_DOWN); } else if_link_state_change(sc->ifp, LINK_STATE_DOWN); } @@ -1947,103 +1939,13 @@ ndis_start(ifp) return; } -static int -ndis_80211transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct ndis_softc *sc = ic->ic_softc; - ndis_packet **p0 = NULL, *p = NULL; - int status; - - NDIS_LOCK(sc); - if (!sc->ndis_link || !sc->ndis_running) { - NDIS_UNLOCK(sc); - return (ENXIO); - } - - if (sc->ndis_txpending == 0) { - NDIS_UNLOCK(sc); - return (ENOBUFS); - } - - p0 = &sc->ndis_txarray[sc->ndis_txidx]; - - NdisAllocatePacket(&status, - &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool); - - if (status != NDIS_STATUS_SUCCESS) { - NDIS_UNLOCK(sc); - return (ENOBUFS); - } - - if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) { - NDIS_UNLOCK(sc); - return (ENOBUFS); - } - - /* - * Save pointer to original mbuf - * so we can free it later. - */ - - p = sc->ndis_txarray[sc->ndis_txidx]; - p->np_txidx = sc->ndis_txidx; - p->np_m0 = m; - p->np_oob.npo_status = NDIS_STATUS_PENDING; - - /* - * Do scatter/gather processing, if driver requested it. - */ - if (sc->ndis_sc) { - bus_dmamap_load_mbuf(sc->ndis_ttag, - sc->ndis_tmaps[sc->ndis_txidx], m, - ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT); - bus_dmamap_sync(sc->ndis_ttag, - sc->ndis_tmaps[sc->ndis_txidx], - BUS_DMASYNC_PREREAD); - p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist; - } - - NDIS_INC(sc); - sc->ndis_txpending--; - - /* - * Set a timeout in case the chip goes out to lunch. - */ - sc->ndis_tx_timer = 5; - NDIS_UNLOCK(sc); - - /* - * According to NDIS documentation, if a driver exports - * a MiniportSendPackets() routine, we prefer that over - * a MiniportSend() routine (which sends just a single - * packet). - */ - if (sc->ndis_chars->nmc_sendmulti_func != NULL) - ndis_send_packets(sc, p0, 1); - else - ndis_send_packet(sc, p); - - return (0); -} - static void -ndis_80211parent(struct ieee80211com *ic) -{ - struct ndis_softc *sc = ic->ic_softc; - - /*NDIS_LOCK(sc);*/ - if (ic->ic_nrunning > 0) { - if (!sc->ndis_running) - ndis_init(sc); - } else if (sc->ndis_running) - ndis_stop(sc); - /*NDIS_UNLOCK(sc);*/ -} - -static void -ndis_init(void *xsc) +ndis_init(xsc) + void *xsc; { struct ndis_softc *sc = xsc; + struct ifnet *ifp = sc->ifp; + struct ieee80211com *ic = ifp->if_l2com; int i, len, error; /* @@ -2069,21 +1971,17 @@ ndis_init(void *xsc) } } + /* Init our MAC address */ + /* Program the packet filter */ - sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED | - NDIS_PACKET_TYPE_BROADCAST; - if (sc->ndis_80211) { - struct ieee80211com *ic = &sc->ndis_ic; + sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED; - if (ic->ic_promisc > 0) - sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - } else { - struct ifnet *ifp = sc->ifp; + if (ifp->if_flags & IFF_BROADCAST) + sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST; - if (ifp->if_flags & IFF_PROMISC) - sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - } + if (ifp->if_flags & IFF_PROMISC) + sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; len = sizeof(sc->ndis_filter); @@ -2096,10 +1994,7 @@ ndis_init(void *xsc) /* * Set lookahead. */ - if (sc->ndis_80211) - i = ETHERMTU; - else - i = sc->ifp->if_mtu; + i = ifp->if_mtu; len = sizeof(i); ndis_set_info(sc, OID_GEN_CURRENT_LOOKAHEAD, &i, &len); @@ -2117,12 +2012,10 @@ ndis_init(void *xsc) sc->ndis_txpending = sc->ndis_maxpkts; sc->ndis_link = 0; - if (!sc->ndis_80211) { - if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN); - sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; - sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - } + if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN); + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->ndis_tx_timer = 0; /* @@ -2136,12 +2029,11 @@ ndis_init(void *xsc) sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs; callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc); - sc->ndis_running = 1; NDIS_UNLOCK(sc); /* XXX force handling */ if (sc->ndis_80211) - ieee80211_start_all(&sc->ndis_ic); /* start all vap's */ + ieee80211_start_all(ic); /* start all vap's */ } /* @@ -2209,12 +2101,16 @@ ndis_ifmedia_sts(ifp, ifmr) } static int -ndis_set_cipher(struct ndis_softc *sc, int cipher) +ndis_set_cipher(sc, cipher) + struct ndis_softc *sc; + int cipher; { - struct ieee80211com *ic = &sc->ndis_ic; + struct ieee80211com *ic; int rval = 0, len; uint32_t arg, save; + ic = sc->ifp->if_l2com; + len = sizeof(arg); if (cipher == WPA_CSE_WEP40 || cipher == WPA_CSE_WEP104) { @@ -2343,7 +2239,7 @@ static void ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211vap *vap = ifp->if_softc; - struct ndis_softc *sc = vap->iv_ic->ic_softc; + struct ndis_softc *sc = vap->iv_ic->ic_ifp->if_softc; uint32_t txrate; int len; @@ -2357,14 +2253,20 @@ ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr) } static void -ndis_setstate_80211(struct ndis_softc *sc) +ndis_setstate_80211(sc) + struct ndis_softc *sc; { - struct ieee80211com *ic = &sc->ndis_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211com *ic; + struct ieee80211vap *vap; ndis_80211_macaddr bssid; ndis_80211_config config; int rval = 0, len; uint32_t arg; + struct ifnet *ifp; + + ifp = sc->ifp; + ic = ifp->if_l2com; + vap = TAILQ_FIRST(&ic->ic_vaps); if (!NDIS_INITIALIZED(sc)) { DPRINTF(("%s: NDIS not initialized\n", __func__)); @@ -2469,7 +2371,7 @@ ndis_setstate_80211(struct ndis_softc *sc) /* Set the BSSID to our value so the driver doesn't associate */ len = IEEE80211_ADDR_LEN; - bcopy(vap->iv_myaddr, bssid, len); + bcopy(IF_LLADDR(ifp), bssid, len); DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":")); rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len); if (rval) @@ -2478,14 +2380,22 @@ ndis_setstate_80211(struct ndis_softc *sc) } static void -ndis_auth_and_assoc(struct ndis_softc *sc, struct ieee80211vap *vap) +ndis_auth_and_assoc(sc, vap) + struct ndis_softc *sc; + struct ieee80211vap *vap; { - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211com *ic; + struct ieee80211_node *ni; ndis_80211_ssid ssid; ndis_80211_macaddr bssid; ndis_80211_wep wep; int i, rval = 0, len, error; uint32_t arg; + struct ifnet *ifp; + + ifp = sc->ifp; + ic = ifp->if_l2com; + ni = vap->iv_bss; if (!NDIS_INITIALIZED(sc)) { DPRINTF(("%s: NDIS not initialized\n", __func__)); @@ -2652,7 +2562,7 @@ ndis_auth_and_assoc(struct ndis_softc *sc, struct ieee80211vap *vap) vap->iv_opmode != IEEE80211_M_IBSS) bcopy(ni->ni_bssid, bssid, len); else - bcopy(ieee80211broadcastaddr, bssid, len); + bcopy(ifp->if_broadcastaddr, bssid, len); DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":")); rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len); @@ -2717,9 +2627,12 @@ ndis_get_bssid_list(sc, bl) } static int -ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc) +ndis_get_assoc(sc, assoc) + struct ndis_softc *sc; + ndis_wlan_bssid_ex **assoc; { - struct ieee80211com *ic = &sc->ndis_ic; + struct ifnet *ifp = sc->ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap; struct ieee80211_node *ni; ndis_80211_bssid_list_ex *bl; @@ -2766,15 +2679,22 @@ ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc) } static void -ndis_getstate_80211(struct ndis_softc *sc) +ndis_getstate_80211(sc) + struct ndis_softc *sc; { - struct ieee80211com *ic = &sc->ndis_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211com *ic; + struct ieee80211vap *vap; + struct ieee80211_node *ni; ndis_wlan_bssid_ex *bs; int rval, len, i = 0; int chanflag; uint32_t arg; + struct ifnet *ifp; + + ifp = sc->ifp; + ic = ifp->if_l2com; + vap = TAILQ_FIRST(&ic->ic_vaps); + ni = vap->iv_bss; if (!NDIS_INITIALIZED(sc)) return; @@ -2893,7 +2813,7 @@ ndis_ioctl(ifp, command, data) switch (command) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - if (sc->ndis_running && + if (ifp->if_drv_flags & IFF_DRV_RUNNING && ifp->if_flags & IFF_PROMISC && !(sc->ndis_if_flags & IFF_PROMISC)) { sc->ndis_filter |= @@ -2902,7 +2822,7 @@ ndis_ioctl(ifp, command, data) error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, &sc->ndis_filter, &i); - } else if (sc->ndis_running && + } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && !(ifp->if_flags & IFF_PROMISC) && sc->ndis_if_flags & IFF_PROMISC) { sc->ndis_filter &= @@ -2914,7 +2834,7 @@ ndis_ioctl(ifp, command, data) } else ndis_init(sc); } else { - if (sc->ndis_running) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ndis_stop(sc); } sc->ndis_if_flags = ifp->if_flags; @@ -2948,48 +2868,101 @@ ndis_ioctl(ifp, command, data) } static int -ndis_80211ioctl(struct ieee80211com *ic, u_long cmd, void *data) +ndis_ioctl_80211(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; { - struct ndis_softc *sc = ic->ic_softc; - struct ifreq *ifr = data; - struct ndis_oid_data oid; - struct ndis_evt evt; - void *oidbuf = NULL; - int error = 0; - - if ((error = priv_check(curthread, PRIV_DRIVER)) != 0) - return (error); + struct ndis_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + struct ndis_oid_data oid; + struct ndis_evt evt; + void *oidbuf; + int error = 0; - switch (cmd) { + switch (command) { + case SIOCSIFFLAGS: + /*NDIS_LOCK(sc);*/ + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + ndis_init(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ndis_stop(sc); + } + sc->ndis_if_flags = ifp->if_flags; + error = 0; + /*NDIS_UNLOCK(sc);*/ + break; case SIOCGDRVSPEC: - case SIOCSDRVSPEC: - error = copyin(ifr->ifr_data, &oid, sizeof(oid)); + if ((error = priv_check(curthread, PRIV_DRIVER))) + break; + error = copyin(ifr->ifr_data, &oid, sizeof(oid)); if (error) break; - oidbuf = malloc(oid.len, M_TEMP, M_WAITOK | M_ZERO); - error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); - } - - if (error) { - free(oidbuf, M_TEMP); - return (error); - } - - switch (cmd) { - case SIOCGDRVSPEC: + oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO); + if (oidbuf == NULL) { + error = ENOMEM; + break; + } + error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(&oid, ifr->ifr_data, sizeof(oid)); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); + free(oidbuf, M_TEMP); break; case SIOCSDRVSPEC: + if ((error = priv_check(curthread, PRIV_DRIVER))) + break; + error = copyin(ifr->ifr_data, &oid, sizeof(oid)); + if (error) + break; + oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO); + if (oidbuf == NULL) { + error = ENOMEM; + break; + } + error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(&oid, ifr->ifr_data, sizeof(oid)); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); + free(oidbuf, M_TEMP); break; case SIOCGPRIVATE_0: + if ((error = priv_check(curthread, PRIV_DRIVER))) + break; NDIS_LOCK(sc); if (sc->ndis_evt[sc->ndis_evtcidx].ne_sts == 0) { error = ENOENT; NDIS_UNLOCK(sc); break; } - error = copyin(ifr->ifr_data, &evt, sizeof(evt)); + error = copyin(ifr->ifr_data, &evt, sizeof(evt)); if (error) { NDIS_UNLOCK(sc); break; @@ -3021,32 +2994,30 @@ ndis_80211ioctl(struct ieee80211com *ic, u_long cmd, void *data) NDIS_EVTINC(sc->ndis_evtcidx); NDIS_UNLOCK(sc); break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, command); + break; + case SIOCGIFADDR: + error = ether_ioctl(ifp, command, data); + break; default: - error = ENOTTY; + error = EINVAL; break; } - - switch (cmd) { - case SIOCGDRVSPEC: - case SIOCSDRVSPEC: - error = copyout(&oid, ifr->ifr_data, sizeof(oid)); - if (error) - break; - error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); - } - - free(oidbuf, M_TEMP); - return (error); } int -ndis_del_key(struct ieee80211vap *vap, const struct ieee80211_key *key) +ndis_del_key(vap, key) + struct ieee80211vap *vap; + const struct ieee80211_key *key; { - struct ndis_softc *sc = vap->iv_ic->ic_softc; + struct ndis_softc *sc; ndis_80211_key rkey; int len, error = 0; + sc = vap->iv_ic->ic_ifp->if_softc; + bzero((char *)&rkey, sizeof(rkey)); len = sizeof(rkey); @@ -3070,13 +3041,19 @@ ndis_del_key(struct ieee80211vap *vap, const struct ieee80211_key *key) * set after initial authentication with the AP. */ static int -ndis_add_key(struct ieee80211vap *vap, const struct ieee80211_key *key, - const uint8_t mac[IEEE80211_ADDR_LEN]) +ndis_add_key(vap, key, mac) + struct ieee80211vap *vap; + const struct ieee80211_key *key; + const uint8_t mac[IEEE80211_ADDR_LEN]; { - struct ndis_softc *sc = vap->iv_ic->ic_softc; + struct ndis_softc *sc; + struct ifnet *ifp; ndis_80211_key rkey; int len, error = 0; + ifp = vap->iv_ic->ic_ifp; + sc = ifp->if_softc; + switch (key->wk_cipher->ic_cipher) { case IEEE80211_CIPHER_TKIP: @@ -3100,7 +3077,7 @@ ndis_add_key(struct ieee80211vap *vap, const struct ieee80211_key *key, rkey.nk_keyidx |= 1 << 31; if (key->wk_flags & IEEE80211_KEY_GROUP) { - bcopy(ieee80211broadcastaddr, + bcopy(ifp->if_broadcastaddr, rkey.nk_bssid, IEEE80211_ADDR_LEN); } else { bcopy(vap->iv_bss->ni_bssid, @@ -3161,18 +3138,19 @@ ndis_resettask(d, arg) * RX and TX lists. */ static void -ndis_stop(struct ndis_softc *sc) +ndis_stop(sc) + struct ndis_softc *sc; { + struct ifnet *ifp; int i; + ifp = sc->ifp; callout_drain(&sc->ndis_stat_callout); NDIS_LOCK(sc); sc->ndis_tx_timer = 0; sc->ndis_link = 0; - if (!sc->ndis_80211) - sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - sc->ndis_running = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); NDIS_UNLOCK(sc); if (sc->ndis_iftype != PNPBus || @@ -3214,7 +3192,8 @@ ndis_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ndis_vap *nvp = NDIS_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct ndis_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ndis_softc *sc = ifp->if_softc; enum ieee80211_state ostate; DPRINTF(("%s: %s -> %s\n", __func__, @@ -3260,8 +3239,8 @@ ndis_scan(void *arg) static void ndis_scan_results(struct ndis_softc *sc) { - struct ieee80211com *ic = &sc->ndis_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211com *ic; + struct ieee80211vap *vap; ndis_80211_bssid_list_ex *bl; ndis_wlan_bssid_ex *wb; struct ieee80211_scanparams sp; @@ -3273,6 +3252,8 @@ ndis_scan_results(struct ndis_softc *sc) uint8_t rates[2+IEEE80211_RATE_MAXSIZE]; uint8_t *frm, *efrm; + ic = sc->ifp->if_l2com; + vap = TAILQ_FIRST(&ic->ic_vaps); saved_chan = ic->ic_curchan; noise = -96; @@ -3348,7 +3329,8 @@ done: static void ndis_scan_start(struct ieee80211com *ic) { - struct ndis_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ndis_softc *sc = ifp->if_softc; struct ieee80211vap *vap; struct ieee80211_scan_state *ss; ndis_80211_ssid ssid; @@ -3409,7 +3391,7 @@ ndis_scan_mindwell(struct ieee80211_scan_state *ss) static void ndis_scan_end(struct ieee80211com *ic) { - struct ndis_softc *sc = ic->ic_softc; + struct ndis_softc *sc = ic->ic_ifp->if_softc; ndis_scan_results(sc); } diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index e3b1a39..f98db0a 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -152,22 +152,8 @@ struct ndisusb_task { }; struct ndis_softc { - u_int ndis_80211:1, - ndis_link:1, - ndis_running:1; - union { - struct { /* Ethernet */ - struct ifnet *ifp; - struct ifmedia ifmedia; - int ndis_if_flags; - }; - struct { /* Wireless */ - struct ieee80211com ndis_ic; - struct callout ndis_scan_callout; - int (*ndis_newstate)(struct ieee80211com *, - enum ieee80211_state, int); - }; - }; + struct ifnet *ifp; + struct ifmedia ifmedia; /* media info */ u_long ndis_hwassist; uint32_t ndis_v4tx; uint32_t ndis_v4rx; @@ -194,6 +180,7 @@ struct ndis_softc { ndis_miniport_block *ndis_block; ndis_miniport_characteristics *ndis_chars; interface_type ndis_type; + struct callout ndis_scan_callout; struct callout ndis_stat_callout; int ndis_maxpkts; ndis_oid *ndis_oids; @@ -205,9 +192,13 @@ struct ndis_softc { int ndis_sc; ndis_cfg *ndis_regvals; struct nch ndis_cfglist_head; + int ndis_80211; + int ndis_link; uint32_t ndis_sts; uint32_t ndis_filter; + int ndis_if_flags; int ndis_skip; + int ndis_devidx; interface_type ndis_iftype; driver_object *ndis_dobj; @@ -226,9 +217,11 @@ struct ndis_softc { struct ndis_evt ndis_evt[NDIS_EVENTS]; int ndis_evtpidx; int ndis_evtcidx; - struct mbufq ndis_rxqueue; + struct ifqueue ndis_rxqueue; kspin_lock ndis_rxlock; + int (*ndis_newstate)(struct ieee80211com *, + enum ieee80211_state, int); int ndis_tx_timer; int ndis_hang_timer; diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c index 1ffd24c..d3eb85e 100644 --- a/sys/dev/ipw/if_ipw.c +++ b/sys/dev/ipw/if_ipw.c @@ -127,14 +127,14 @@ static void ipw_intr(void *); static void ipw_dma_map_addr(void *, bus_dma_segment_t *, int, int); static const char * ipw_cmdname(int); static int ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t); -static int ipw_tx_start(struct ipw_softc *, struct mbuf *, +static int ipw_tx_start(struct ifnet *, struct mbuf *, struct ieee80211_node *); static int ipw_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static int ipw_transmit(struct ieee80211com *, struct mbuf *); -static void ipw_start(struct ipw_softc *); +static void ipw_start(struct ifnet *); +static void ipw_start_locked(struct ifnet *); static void ipw_watchdog(void *); -static void ipw_parent(struct ieee80211com *); +static int ipw_ioctl(struct ifnet *, u_long, caddr_t); static void ipw_stop_master(struct ipw_softc *); static int ipw_enable(struct ipw_softc *); static int ipw_disable(struct ipw_softc *); @@ -220,16 +220,18 @@ static int ipw_attach(device_t dev) { struct ipw_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; struct ieee80211_channel *c; uint16_t val; int error, i; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); - mbufq_init(&sc->sc_snd, ifqmaxlen); + TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc); callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); @@ -266,6 +268,24 @@ ipw_attach(device_t dev) goto fail2; } + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + goto fail3; + } + ic = ifp->if_l2com; + + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = ipw_init; + ifp->if_ioctl = ipw_ioctl; + ifp->if_start = ipw_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(dev); ic->ic_opmode = IEEE80211_M_STA; @@ -283,14 +303,14 @@ ipw_attach(device_t dev) /* read MAC address from EEPROM */ val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0); - ic->ic_macaddr[0] = val >> 8; - ic->ic_macaddr[1] = val & 0xff; + macaddr[0] = val >> 8; + macaddr[1] = val & 0xff; val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 1); - ic->ic_macaddr[2] = val >> 8; - ic->ic_macaddr[3] = val & 0xff; + macaddr[2] = val >> 8; + macaddr[3] = val & 0xff; val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 2); - ic->ic_macaddr[4] = val >> 8; - ic->ic_macaddr[5] = val & 0xff; + macaddr[4] = val >> 8; + macaddr[5] = val & 0xff; /* set supported .11b channels (read from EEPROM) */ if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0) @@ -309,17 +329,16 @@ ipw_attach(device_t dev) if (!(ipw_read_prom_word(sc, IPW_EEPROM_RADIO) & 8)) sc->flags |= IPW_FLAG_HAS_RADIO_SWITCH; - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_scan_start = ipw_scan_start; ic->ic_scan_end = ipw_scan_end; ic->ic_set_channel = ipw_set_channel; ic->ic_scan_curchan = ipw_scan_curchan; ic->ic_scan_mindwell = ipw_scan_mindwell; ic->ic_raw_xmit = ipw_raw_xmit; + ic->ic_vap_create = ipw_vap_create; ic->ic_vap_delete = ipw_vap_delete; - ic->ic_transmit = ipw_transmit; - ic->ic_parent = ipw_parent; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -347,13 +366,15 @@ ipw_attach(device_t dev) NULL, ipw_intr, sc, &sc->sc_ih); if (error != 0) { device_printf(dev, "could not set up interrupt\n"); - goto fail3; + goto fail4; } if (bootverbose) ieee80211_announce(ic); return 0; +fail4: + if_free(ifp); fail3: ipw_release(sc); fail2: @@ -370,7 +391,8 @@ static int ipw_detach(device_t dev) { struct ipw_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; bus_teardown_intr(dev, sc->irq, sc->sc_ih); @@ -380,7 +402,6 @@ ipw_detach(device_t dev) ieee80211_ifdetach(ic); callout_drain(&sc->sc_wdtimer); - mbufq_drain(&sc->sc_snd); ipw_release(sc); @@ -389,6 +410,8 @@ ipw_detach(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), sc->mem); + if_free(ifp); + if (sc->sc_firmware != NULL) { firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD); sc->sc_firmware = NULL; @@ -405,7 +428,8 @@ ipw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct ipw_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; struct ipw_vap *ivp; struct ieee80211vap *vap; const struct firmware *fp; @@ -463,17 +487,19 @@ ipw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, return NULL; } - ivp = malloc(sizeof(struct ipw_vap), M_80211_VAP, M_WAITOK | M_ZERO); + ivp = (struct ipw_vap *) malloc(sizeof(struct ipw_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (ivp == NULL) + return NULL; vap = &ivp->vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override with driver methods */ ivp->newstate = vap->iv_newstate; vap->iv_newstate = ipw_newstate; /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, ipw_media_status, - mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ipw_media_status); ic->ic_opmode = opmode; return vap; } @@ -801,7 +827,7 @@ static int ipw_suspend(device_t dev) { struct ipw_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; ieee80211_suspend_all(ic); return 0; @@ -811,7 +837,7 @@ static int ipw_resume(device_t dev) { struct ipw_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; pci_write_config(dev, 0x41, 0, 1); @@ -840,7 +866,7 @@ ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; - struct ipw_softc *sc = ic->ic_softc; + struct ipw_softc *sc = ic->ic_ifp->if_softc; /* read current transmission rate from adapter */ vap->iv_bss->ni_txrate = ipw_cvtrate( @@ -853,7 +879,8 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ipw_vap *ivp = IPW_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct ipw_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; enum ieee80211_state ostate; DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, @@ -988,7 +1015,8 @@ static void ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) { #define IEEESTATE(vap) ieee80211_state_name[vap->iv_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); uint32_t state; @@ -1090,7 +1118,8 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) static void ipw_setcurchan(struct ipw_softc *sc, struct ieee80211_channel *chan) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; ic->ic_curchan = chan; ieee80211_radiotap_chan_change(ic); @@ -1103,7 +1132,8 @@ ipw_setcurchan(struct ipw_softc *sc, struct ieee80211_channel *chan) static void ipw_fix_channel(struct ipw_softc *sc, struct mbuf *m) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_channel *c; struct ieee80211_frame *wh; uint8_t subtype; @@ -1148,7 +1178,8 @@ static void ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mbuf *mnew, *m; struct ieee80211_node *ni; bus_addr_t physaddr; @@ -1170,7 +1201,7 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, */ mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (mnew == NULL) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -1191,7 +1222,7 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, panic("%s: could not load old rx mbuf", device_get_name(sc->sc_dev)); } - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -1202,6 +1233,9 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, m = sbuf->m; sbuf->m = mnew; sbd->bd->physaddr = htole32(physaddr); + + /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = le32toh(status->len); rssi = status->rssi + IPW_RSSI_TO_DBM; @@ -1330,6 +1364,7 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd) static void ipw_tx_intr(struct ipw_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct ipw_soft_bd *sbd; uint32_t r, i; @@ -1340,6 +1375,10 @@ ipw_tx_intr(struct ipw_softc *sc) for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) { sbd = &sc->stbd_list[i]; + + if (sbd->type == IPW_SBD_TYPE_DATA) + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ipw_release_sbd(sc, sbd); sc->txfree++; } @@ -1347,13 +1386,15 @@ ipw_tx_intr(struct ipw_softc *sc) /* remember what the firmware has processed */ sc->txold = (r == 0) ? IPW_NTBD - 1 : r - 1; - ipw_start(sc); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ipw_start_locked(ifp); } static void ipw_fatal_error_intr(struct ipw_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); device_printf(sc->sc_dev, "firmware error\n"); @@ -1538,9 +1579,10 @@ ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len) } static int -ipw_tx_start(struct ipw_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) +ipw_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ipw_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; struct ipw_soft_bd *sbd; @@ -1694,42 +1736,38 @@ ipw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return 0; } -static int -ipw_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +ipw_start(struct ifnet *ifp) { - struct ipw_softc *sc = ic->ic_softc; - int error; + struct ipw_softc *sc = ifp->if_softc; IPW_LOCK(sc); - if ((sc->flags & IPW_FLAG_RUNNING) == 0) { - IPW_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - IPW_UNLOCK(sc); - return (error); - } - ipw_start(sc); + ipw_start_locked(ifp); IPW_UNLOCK(sc); - return (0); } static void -ipw_start(struct ipw_softc *sc) +ipw_start_locked(struct ifnet *ifp) { + struct ipw_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; IPW_LOCK_ASSERT(sc); - while (sc->txfree < 1 + IPW_MAX_NSEG && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->txfree < 1 + IPW_MAX_NSEG) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; - if (ipw_tx_start(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if (ipw_tx_start(ifp, m, ni) != 0) { ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } /* start watchdog timer */ @@ -1741,14 +1779,15 @@ static void ipw_watchdog(void *arg) { struct ipw_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IPW_LOCK_ASSERT(sc); if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(ic->ic_oerrors, 1); + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); taskqueue_enqueue(taskqueue_swi, &sc->sc_init_task); } } @@ -1764,27 +1803,45 @@ ipw_watchdog(void *arg) } } } - if (sc->flags & IPW_FLAG_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc); } -static void -ipw_parent(struct ieee80211com *ic) +static int +ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct ipw_softc *sc = ic->ic_softc; - int startall = 0; + struct ipw_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; - IPW_LOCK(sc); - if (ic->ic_nrunning > 0) { - if (!(sc->flags & IPW_FLAG_RUNNING)) { - ipw_init_locked(sc); - startall = 1; + switch (cmd) { + case SIOCSIFFLAGS: + IPW_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + ipw_init_locked(sc); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ipw_stop_locked(sc); } - } else if (sc->flags & IPW_FLAG_RUNNING) - ipw_stop_locked(sc); - IPW_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + IPW_UNLOCK(sc); + 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 @@ -2000,7 +2057,8 @@ ipw_load_firmware(struct ipw_softc *sc, const char *fw, int size) static int ipw_setwepkeys(struct ipw_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 ipw_wep_key wepkey; struct ieee80211_key *wk; @@ -2143,7 +2201,8 @@ done: static int ipw_setchannel(struct ipw_softc *sc, struct ieee80211_channel *chan) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t data; int error; @@ -2158,7 +2217,8 @@ ipw_setchannel(struct ipw_softc *sc, struct ieee80211_channel *chan) static void ipw_assoc(struct ieee80211com *ic, struct ieee80211vap *vap) { - struct ipw_softc *sc = ic->ic_softc; + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; struct ieee80211_node *ni = vap->iv_bss; struct ipw_security security; uint32_t data; @@ -2249,8 +2309,9 @@ done: static void ipw_disassoc(struct ieee80211com *ic, struct ieee80211vap *vap) { + struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ieee80211_node *ni = vap->iv_bss; - struct ipw_softc *sc = ic->ic_softc; + struct ipw_softc *sc = ifp->if_softc; IPW_LOCK(sc); DPRINTF(("Disassociate from %6D\n", ni->ni_bssid, ":")); @@ -2284,20 +2345,22 @@ static void ipw_init(void *priv) { struct ipw_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IPW_LOCK(sc); ipw_init_locked(sc); IPW_UNLOCK(sc); - if (sc->flags & IPW_FLAG_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); /* start all vap's */ } static void ipw_init_locked(struct ipw_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); const struct firmware *fp; const struct ipw_firmware_hdr *hdr; @@ -2381,19 +2444,22 @@ ipw_init_locked(struct ipw_softc *sc) } callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc); - sc->flags |= IPW_FLAG_RUNNING; - sc->flags &= ~IPW_FLAG_INIT_LOCKED; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + + sc->flags &=~ IPW_FLAG_INIT_LOCKED; return; fail: ipw_stop_locked(sc); - sc->flags &= ~IPW_FLAG_INIT_LOCKED; + sc->flags &=~ IPW_FLAG_INIT_LOCKED; } static int ipw_config(struct ipw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ipw_configuration config; uint32_t data; int error; @@ -2438,7 +2504,7 @@ ipw_config(struct ipw_softc *sc) IPW_CFG_PREAMBLE_AUTO | IPW_CFG_802_1x_ENABLE); if (ic->ic_opmode == IEEE80211_M_IBSS) config.flags |= htole32(IPW_CFG_IBSS_AUTO_START); - if (ic->ic_promisc > 0) + if (ifp->if_flags & IFF_PROMISC) config.flags |= htole32(IPW_CFG_PROMISCUOUS); config.bss_chan = htole32(0x3fff); /* channels 1-14 */ config.ibss_chan = htole32(0x7ff); /* channels 1-11 */ @@ -2496,6 +2562,7 @@ ipw_stop(void *priv) static void ipw_stop_locked(struct ipw_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int i; IPW_LOCK_ASSERT(sc); @@ -2512,7 +2579,7 @@ ipw_stop_locked(struct ipw_softc *sc) ipw_release_sbd(sc, &sc->stbd_list[i]); sc->sc_tx_timer = 0; - sc->flags &= ~IPW_FLAG_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } static int @@ -2610,7 +2677,8 @@ ipw_write_mem_1(struct ipw_softc *sc, bus_size_t offset, const uint8_t *datap, static void ipw_scan_start(struct ieee80211com *ic) { - struct ipw_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; IPW_LOCK(sc); ipw_scan(sc); @@ -2620,7 +2688,8 @@ ipw_scan_start(struct ieee80211com *ic) static void ipw_set_channel(struct ieee80211com *ic) { - struct ipw_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; IPW_LOCK(sc); if (ic->ic_opmode == IEEE80211_M_MONITOR) { @@ -2646,7 +2715,8 @@ ipw_scan_mindwell(struct ieee80211_scan_state *ss) static void ipw_scan_end(struct ieee80211com *ic) { - struct ipw_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; IPW_LOCK(sc); sc->flags &= ~IPW_FLAG_SCANNING; diff --git a/sys/dev/ipw/if_ipwvar.h b/sys/dev/ipw/if_ipwvar.h index aa3ba5b..cca050f 100644 --- a/sys/dev/ipw/if_ipwvar.h +++ b/sys/dev/ipw/if_ipwvar.h @@ -87,8 +87,7 @@ struct ipw_vap { #define IPW_VAP(vap) ((struct ipw_vap *)(vap)) struct ipw_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct mtx sc_mtx; @@ -105,7 +104,6 @@ struct ipw_softc { #define IPW_FLAG_BUSY 0x0040 #define IPW_FLAG_ASSOCIATING 0x0080 #define IPW_FLAG_ASSOCIATED 0x0100 -#define IPW_FLAG_RUNNING 0x0200 struct resource *irq; struct resource *mem; diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c index 73631ea..fecbe89 100644 --- a/sys/dev/iwi/if_iwi.c +++ b/sys/dev/iwi/if_iwi.c @@ -166,15 +166,14 @@ static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); static void iwi_intr(void *); static int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t); static void iwi_write_ibssnode(struct iwi_softc *, const u_int8_t [], int); -static int iwi_tx_start(struct iwi_softc *, struct mbuf *, +static int iwi_tx_start(struct ifnet *, struct mbuf *, struct ieee80211_node *, int); static int iwi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void iwi_start(struct iwi_softc *); -static int iwi_transmit(struct ieee80211com *, struct mbuf *); +static void iwi_start_locked(struct ifnet *); +static void iwi_start(struct ifnet *); static void iwi_watchdog(void *); -static int iwi_ioctl(struct ieee80211com *, u_long, void *); -static void iwi_parent(struct ieee80211com *); +static int iwi_ioctl(struct ifnet *, u_long, caddr_t); static void iwi_stop_master(struct iwi_softc *); static int iwi_reset(struct iwi_softc *); static int iwi_load_ucode(struct iwi_softc *, const struct iwi_fw *); @@ -270,15 +269,23 @@ static int iwi_attach(device_t dev) { struct iwi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; uint16_t val; int i, error; uint8_t bands; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + return ENXIO; + } + ic = ifp->if_l2com; + IWI_LOCK_INIT(sc); - mbufq_init(&sc->sc_snd, ifqmaxlen); sc->sc_unr = new_unrhdr(1, IWI_MAX_IBSSNODE-1, &sc->sc_mtx); @@ -346,6 +353,17 @@ iwi_attach(device_t dev) iwi_wme_init(sc); + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = iwi_init; + ifp->if_ioctl = iwi_ioctl; + ifp->if_start = iwi_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(dev); ic->ic_opmode = IEEE80211_M_STA; @@ -367,14 +385,14 @@ iwi_attach(device_t dev) /* read MAC address from EEPROM */ val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); - ic->ic_macaddr[0] = val & 0xff; - ic->ic_macaddr[1] = val >> 8; + macaddr[0] = val & 0xff; + macaddr[1] = val >> 8; val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1); - ic->ic_macaddr[2] = val & 0xff; - ic->ic_macaddr[3] = val >> 8; + macaddr[2] = val & 0xff; + macaddr[3] = val >> 8; val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2); - ic->ic_macaddr[4] = val & 0xff; - ic->ic_macaddr[5] = val >> 8; + macaddr[4] = val & 0xff; + macaddr[5] = val >> 8; bands = 0; setbit(&bands, IEEE80211_MODE_11B); @@ -383,7 +401,7 @@ iwi_attach(device_t dev) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); /* override default methods */ ic->ic_node_alloc = iwi_node_alloc; sc->sc_node_free = ic->ic_node_free; @@ -398,9 +416,6 @@ iwi_attach(device_t dev) ic->ic_vap_create = iwi_vap_create; ic->ic_vap_delete = iwi_vap_delete; - ic->ic_ioctl = iwi_ioctl; - ic->ic_transmit = iwi_transmit; - ic->ic_parent = iwi_parent; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -435,7 +450,8 @@ static int iwi_detach(device_t dev) { struct iwi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; bus_teardown_intr(dev, sc->irq, sc->sc_ih); @@ -466,10 +482,11 @@ iwi_detach(device_t dev) sc->mem); delete_unrhdr(sc->sc_unr); - mbufq_drain(&sc->sc_snd); IWI_LOCK_DESTROY(sc); + if_free(ifp); + return 0; } @@ -479,7 +496,8 @@ iwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct iwi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwi_softc *sc = ifp->if_softc; struct iwi_vap *ivp; struct ieee80211vap *vap; int i; @@ -501,9 +519,12 @@ iwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (iwi_init_fw_dma(sc, i)) return NULL; - ivp = malloc(sizeof(struct iwi_vap), M_80211_VAP, M_WAITOK | M_ZERO); + ivp = (struct iwi_vap *) malloc(sizeof(struct iwi_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (ivp == NULL) + return NULL; vap = &ivp->iwi_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override the default, the setting comes from the linux driver */ vap->iv_bmissthreshold = 24; /* override with driver methods */ @@ -511,8 +532,7 @@ iwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, vap->iv_newstate = iwi_newstate; /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, iwi_media_status, - mac); + ieee80211_vap_attach(vap, ieee80211_media_change, iwi_media_status); ic->ic_opmode = opmode; return vap; } @@ -839,7 +859,7 @@ static int iwi_suspend(device_t dev) { struct iwi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; ieee80211_suspend_all(ic); return 0; @@ -849,7 +869,7 @@ static int iwi_resume(device_t dev) { struct iwi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; pci_write_config(dev, 0x41, 0, 1); @@ -875,7 +895,7 @@ static void iwi_node_free(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct iwi_softc *sc = ic->ic_softc; + struct iwi_softc *sc = ic->ic_ifp->if_softc; struct iwi_node *in = (struct iwi_node *)ni; if (in->in_station != -1) { @@ -919,7 +939,7 @@ iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; - struct iwi_softc *sc = ic->ic_softc; + struct iwi_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; /* read current transmission rate from adapter */ @@ -935,7 +955,8 @@ iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct iwi_vap *ivp = IWI_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct iwi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwi_softc *sc = ifp->if_softc; IWI_LOCK_DECL; DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, @@ -1040,7 +1061,7 @@ iwi_wme_init(struct iwi_softc *sc) static int iwi_wme_setparams(struct iwi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; const struct wmeParams *wmep; int ac; @@ -1074,7 +1095,7 @@ iwi_update_wme(void *arg, int npending) static int iwi_wme_update(struct ieee80211com *ic) { - struct iwi_softc *sc = ic->ic_softc; + struct iwi_softc *sc = ic->ic_ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); /* @@ -1168,7 +1189,8 @@ iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr) static void iwi_setcurchan(struct iwi_softc *sc, int chan) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; sc->curchan = chan; ieee80211_radiotap_chan_change(ic); @@ -1178,7 +1200,8 @@ static void iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, struct iwi_frame *frame) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mbuf *mnew, *m; struct ieee80211_node *ni; int type, error, framelen; @@ -1214,7 +1237,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, */ mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (mnew == NULL) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -1235,7 +1258,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, panic("%s: could not load old rx mbuf", device_get_name(sc->sc_dev)); } - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -1248,6 +1271,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, CSR_WRITE_4(sc, data->reg, data->physaddr); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) + sizeof (struct iwi_frame) + framelen; @@ -1386,7 +1410,8 @@ iwi_notif_link_quality(struct iwi_softc *sc, struct iwi_notif *notif) static void iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) { - 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 iwi_notif_scan_channel *chan; struct iwi_notif_scan_complete *scan; @@ -1607,33 +1632,47 @@ iwi_rx_intr(struct iwi_softc *sc) static void iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) { + struct ifnet *ifp = sc->sc_ifp; struct iwi_tx_data *data; uint32_t hw; hw = CSR_READ_4(sc, txq->csr_ridx); - while (txq->next != hw) { + for (; txq->next != hw;) { data = &txq->data[txq->next]; - DPRINTFN(15, ("tx done idx=%u\n", txq->next)); + bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(txq->data_dmat, data->map); - ieee80211_tx_complete(data->ni, data->m, 0); - data->ni = NULL; + if (data->m->m_flags & M_TXCB) + ieee80211_process_callback(data->ni, data->m, 0/*XXX*/); + m_freem(data->m); data->m = NULL; + ieee80211_free_node(data->ni); + data->ni = NULL; + + DPRINTFN(15, ("tx done idx=%u\n", txq->next)); + + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + txq->queued--; txq->next = (txq->next + 1) % IWI_TX_RING_COUNT; } + sc->sc_tx_timer = 0; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if (sc->sc_softled) iwi_led_event(sc, IWI_LED_TX); - iwi_start(sc); + + iwi_start_locked(ifp); } static void iwi_fatal_error_intr(struct iwi_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); device_printf(sc->sc_dev, "firmware error\n"); @@ -1649,8 +1688,10 @@ iwi_fatal_error_intr(struct iwi_softc *sc) static void iwi_radio_off_intr(struct iwi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - ieee80211_runtask(&sc->sc_ic, &sc->sc_radiofftask); + ieee80211_runtask(ic, &sc->sc_radiofftask); } static void @@ -1765,9 +1806,10 @@ iwi_write_ibssnode(struct iwi_softc *sc, } static int -iwi_tx_start(struct iwi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, +iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni, int ac) { + struct iwi_softc *sc = ifp->if_softc; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct iwi_node *in = (struct iwi_node *)ni; @@ -1810,10 +1852,9 @@ iwi_tx_start(struct iwi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, in->in_station = alloc_unr(sc->sc_unr); if (in->in_station == -1) { /* h/w table is full */ - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); m_freem(m0); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return 0; } iwi_write_ibssnode(sc, @@ -1939,139 +1980,141 @@ iwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return 0; } -static int -iwi_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct iwi_softc *sc = ic->ic_softc; - int error; - IWI_LOCK_DECL; - - IWI_LOCK(sc); - if (!sc->sc_running) { - IWI_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - IWI_UNLOCK(sc); - return (error); - } - iwi_start(sc); - IWI_UNLOCK(sc); - return (0); -} - static void -iwi_start(struct iwi_softc *sc) +iwi_start_locked(struct ifnet *ifp) { + struct iwi_softc *sc = ifp->if_softc; struct mbuf *m; struct ieee80211_node *ni; int ac; IWI_LOCK_ASSERT(sc); - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; ac = M_WME_GETAC(m); if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) { /* there is no place left in this ring; tail drop */ /* XXX tail drop */ - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; - if (iwi_tx_start(sc, m, ni, ac) != 0) { + if (iwi_tx_start(ifp, m, ni, ac) != 0) { ieee80211_free_node(ni); - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } + sc->sc_tx_timer = 5; } } static void +iwi_start(struct ifnet *ifp) +{ + struct iwi_softc *sc = ifp->if_softc; + IWI_LOCK_DECL; + + IWI_LOCK(sc); + iwi_start_locked(ifp); + IWI_UNLOCK(sc); +} + +static void iwi_watchdog(void *arg) { struct iwi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IWI_LOCK_ASSERT(sc); if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(ic->ic_oerrors, 1); + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_runtask(ic, &sc->sc_restarttask); } } if (sc->sc_state_timer > 0) { if (--sc->sc_state_timer == 0) { - device_printf(sc->sc_dev, - "firmware stuck in state %d, resetting\n", + if_printf(ifp, "firmware stuck in state %d, resetting\n", sc->fw_state); - if (sc->fw_state == IWI_FW_SCANNING) + if (sc->fw_state == IWI_FW_SCANNING) { + struct ieee80211com *ic = ifp->if_l2com; ieee80211_cancel_scan(TAILQ_FIRST(&ic->ic_vaps)); + } ieee80211_runtask(ic, &sc->sc_restarttask); sc->sc_state_timer = 3; } } if (sc->sc_busy_timer > 0) { if (--sc->sc_busy_timer == 0) { - device_printf(sc->sc_dev, - "firmware command timeout, resetting\n"); + if_printf(ifp, "firmware command timeout, resetting\n"); ieee80211_runtask(ic, &sc->sc_restarttask); } } callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); } -static void -iwi_parent(struct ieee80211com *ic) -{ - struct iwi_softc *sc = ic->ic_softc; - int startall = 0; - IWI_LOCK_DECL; - - IWI_LOCK(sc); - if (ic->ic_nrunning > 0) { - if (!sc->sc_running) { - iwi_init_locked(sc); - startall = 1; - } - } else if (sc->sc_running) - iwi_stop_locked(sc); - IWI_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); -} - static int -iwi_ioctl(struct ieee80211com *ic, u_long cmd, void *data) +iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct ifreq *ifr = data; - struct iwi_softc *sc = ic->ic_softc; - int error; + struct iwi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; IWI_LOCK_DECL; - IWI_LOCK(sc); switch (cmd) { + case SIOCSIFFLAGS: + IWI_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + iwi_init_locked(sc); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + iwi_stop_locked(sc); + } + IWI_UNLOCK(sc); + 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; case SIOCGIWISTATS: + IWI_LOCK(sc); /* XXX validate permissions/memory/etc? */ error = copyout(&sc->sc_linkqual, ifr->ifr_data, sizeof(struct iwi_notif_link_quality)); + IWI_UNLOCK(sc); break; case SIOCZIWISTATS: + IWI_LOCK(sc); memset(&sc->sc_linkqual, 0, sizeof(struct iwi_notif_link_quality)); + IWI_UNLOCK(sc); error = 0; break; default: - error = ENOTTY; + error = EINVAL; break; } - IWI_UNLOCK(sc); - - return (error); + return error; } static void @@ -2550,7 +2593,8 @@ iwi_setwepkeys(struct iwi_softc *sc, struct ieee80211vap *vap) static int iwi_config(struct iwi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct iwi_configuration config; struct iwi_rateset rs; struct iwi_txpower power; @@ -2559,8 +2603,8 @@ iwi_config(struct iwi_softc *sc) IWI_LOCK_ASSERT(sc); - DPRINTF(("Setting MAC address to %6D\n", ic->ic_macaddr, ":")); - error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, + DPRINTF(("Setting MAC address to %6D\n", IF_LLADDR(ifp), ":")); + error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, IF_LLADDR(ifp), IEEE80211_ADDR_LEN); if (error != 0) return error; @@ -2680,7 +2724,7 @@ iwi_monitor_scan(void *arg, int npending) static int iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int allchan) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; struct ieee80211_channel *chan; struct ieee80211_scan_state *ss; struct iwi_scan_ext scan; @@ -2697,6 +2741,7 @@ iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int allchan) } IWI_STATE_BEGIN(sc, IWI_FW_SCANNING); + ic = sc->sc_ifp->if_l2com; ss = ic->ic_scan; memset(&scan, 0, sizeof scan); @@ -3083,6 +3128,7 @@ error: static void iwi_init_locked(struct iwi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct iwi_rx_data *data; int i; @@ -3156,7 +3202,8 @@ iwi_init_locked(struct iwi_softc *sc) } callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); - sc->sc_running = 1; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; return; fail: IWI_STATE_END(sc, IWI_FW_LOADING); @@ -3168,14 +3215,15 @@ static void iwi_init(void *priv) { struct iwi_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IWI_LOCK_DECL; IWI_LOCK(sc); iwi_init_locked(sc); IWI_UNLOCK(sc); - if (sc->sc_running) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); } @@ -3183,10 +3231,11 @@ static void iwi_stop_locked(void *priv) { struct iwi_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; IWI_LOCK_ASSERT(sc); - sc->sc_running = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); if (sc->sc_softled) { callout_stop(&sc->sc_ledtimer); @@ -3247,7 +3296,7 @@ static void iwi_radio_on(void *arg, int pending) { struct iwi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; device_printf(sc->sc_dev, "radio turned on\n"); @@ -3268,7 +3317,10 @@ iwi_rfkill_poll(void *arg) * it is enabled so we must poll for the latter. */ if (!iwi_getrfkill(sc)) { - ieee80211_runtask(&sc->sc_ic, &sc->sc_radiontask); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + ieee80211_runtask(ic, &sc->sc_radiontask); return; } callout_reset(&sc->sc_rftimer, 2*hz, iwi_rfkill_poll, sc); @@ -3278,7 +3330,7 @@ static void iwi_radio_off(void *arg, int pending) { struct iwi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; IWI_LOCK_DECL; device_printf(sc->sc_dev, "radio turned off\n"); @@ -3542,8 +3594,8 @@ iwi_scan_start(struct ieee80211com *ic) static void iwi_set_channel(struct ieee80211com *ic) { - struct iwi_softc *sc = ic->ic_softc; - + struct ifnet *ifp = ic->ic_ifp; + struct iwi_softc *sc = ifp->if_softc; if (sc->fw_state == IWI_FW_IDLE) iwi_setcurchan(sc, ic->ic_curchan->ic_ieee); } @@ -3552,7 +3604,8 @@ static void iwi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; - struct iwi_softc *sc = vap->iv_ic->ic_softc; + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct iwi_softc *sc = ifp->if_softc; IWI_LOCK_DECL; IWI_LOCK(sc); @@ -3570,7 +3623,8 @@ iwi_scan_mindwell(struct ieee80211_scan_state *ss) static void iwi_scan_end(struct ieee80211com *ic) { - struct iwi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwi_softc *sc = ifp->if_softc; IWI_LOCK_DECL; IWI_LOCK(sc); diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h index 47848e1..b38bbd9 100644 --- a/sys/dev/iwi/if_iwivar.h +++ b/sys/dev/iwi/if_iwivar.h @@ -125,13 +125,11 @@ struct iwi_vap { #define IWI_VAP(vap) ((struct iwi_vap *)(vap)) struct iwi_softc { - struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mbufq sc_snd; - device_t sc_dev; - + struct ifnet *sc_ifp; void (*sc_node_free)(struct ieee80211_node *); + device_t sc_dev; + struct mtx sc_mtx; uint8_t sc_mcast[IEEE80211_ADDR_LEN]; struct unrhdr *sc_unr; @@ -195,8 +193,7 @@ struct iwi_softc { struct task sc_wmetask; /* set wme parameters */ struct task sc_monitortask; - unsigned int sc_running : 1, /* initialized */ - sc_softled : 1, /* enable LED gpio status */ + unsigned int sc_softled : 1, /* enable LED gpio status */ sc_ledstate: 1, /* LED on/off state */ sc_blinking: 1; /* LED blink operation active */ u_int sc_nictype; /* NIC type from EEPROM */ diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index cfed420..3cd5d7b 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -235,11 +235,10 @@ static int iwn_tx_data_raw(struct iwn_softc *, struct mbuf *, static void iwn_xmit_task(void *arg0, int pending); static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static int iwn_transmit(struct ieee80211com *, struct mbuf *); -static void iwn_start_locked(struct iwn_softc *); +static void iwn_start(struct ifnet *); +static void iwn_start_locked(struct ifnet *); static void iwn_watchdog(void *); -static int iwn_ioctl(struct ieee80211com *, u_long , void *); -static void iwn_parent(struct ieee80211com *); +static int iwn_ioctl(struct ifnet *, u_long, caddr_t); static int iwn_cmd(struct iwn_softc *, int, const void *, int, int); static int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *, int); @@ -337,7 +336,7 @@ static void iwn_radio_on(void *, int); static void iwn_radio_off(void *, int); static void iwn_panicked(void *, int); static void iwn_init_locked(struct iwn_softc *); -static void iwn_init(struct iwn_softc *); +static void iwn_init(void *); static void iwn_stop_locked(struct iwn_softc *); static void iwn_stop(struct iwn_softc *); static void iwn_scan_start(struct ieee80211com *); @@ -407,7 +406,9 @@ iwn_attach(device_t dev) { struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); struct ieee80211com *ic; + struct ifnet *ifp; int i, error, rid; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; @@ -463,7 +464,6 @@ iwn_attach(device_t dev) } IWN_LOCK_INIT(sc); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* Read hardware revision and attach. */ sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT) @@ -549,7 +549,14 @@ iwn_attach(device_t dev) /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); - ic = &sc->sc_ic; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + goto fail; + } + + 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 */ @@ -574,7 +581,7 @@ iwn_attach(device_t dev) ; /* Read MAC address, channels, etc from EEPROM. */ - if ((error = iwn_read_eeprom(sc, ic->ic_macaddr)) != 0) { + if ((error = iwn_read_eeprom(sc, macaddr)) != 0) { device_printf(dev, "could not read EEPROM, error %d\n", error); goto fail; @@ -592,7 +599,7 @@ iwn_attach(device_t dev) if (bootverbose) { device_printf(dev, "MIMO %dT%dR, %.4s, address %6D\n", sc->ntxchains, sc->nrxchains, sc->eeprom_domain, - ic->ic_macaddr, ":"); + macaddr, ":"); } if (sc->sc_flags & IWN_FLAG_HAS_11N) { @@ -633,12 +640,19 @@ iwn_attach(device_t dev) ; } - ieee80211_ifattach(ic); + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = iwn_init; + ifp->if_ioctl = iwn_ioctl; + ifp->if_start = iwn_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + ieee80211_ifattach(ic, macaddr); ic->ic_vap_create = iwn_vap_create; - ic->ic_ioctl = iwn_ioctl; - ic->ic_parent = iwn_parent; ic->ic_vap_delete = iwn_vap_delete; - ic->ic_transmit = iwn_transmit; ic->ic_raw_xmit = iwn_raw_xmit; ic->ic_node_alloc = iwn_node_alloc; sc->sc_ampdu_rx_start = ic->ic_ampdu_rx_start; @@ -1279,9 +1293,10 @@ iwn5000_attach(struct iwn_softc *sc, uint16_t pid) static void iwn_radiotap_attach(struct iwn_softc *sc) { - + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); - ieee80211_radiotap_attach(&sc->sc_ic, + ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), IWN_TX_RADIOTAP_PRESENT, &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), @@ -1311,14 +1326,21 @@ iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, struct iwn_softc *sc = ic->ic_softc; struct iwn_vap *ivp; struct ieee80211vap *vap; + uint8_t mac1[IEEE80211_ADDR_LEN]; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - ivp = malloc(sizeof(struct iwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); + IEEE80211_ADDR_COPY(mac1, mac); + + ivp = (struct iwn_vap *) malloc(sizeof(struct iwn_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (ivp == NULL) + return NULL; vap = &ivp->iv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac1); ivp->ctx = IWN_RXON_BSS_CTX; + IEEE80211_ADDR_COPY(ivp->macaddr, mac1); vap->iv_bmissthreshold = 10; /* override default */ /* Override with driver methods. */ ivp->iv_newstate = vap->iv_newstate; @@ -1327,8 +1349,7 @@ iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* Complete setup. */ - ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status, - mac); + ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -1369,19 +1390,24 @@ static int iwn_detach(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; int qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); - if (sc->sc_ic.ic_softc != NULL) { + if (ifp != NULL) { + ic = ifp->if_l2com; + /* Free the mbuf queue and node references */ IWN_LOCK(sc); iwn_xmit_queue_drain(sc); IWN_UNLOCK(sc); - ieee80211_draintask(&sc->sc_ic, &sc->sc_reinit_task); - ieee80211_draintask(&sc->sc_ic, &sc->sc_radioon_task); - ieee80211_draintask(&sc->sc_ic, &sc->sc_radiooff_task); + ieee80211_draintask(ic, &sc->sc_reinit_task); + ieee80211_draintask(ic, &sc->sc_radioon_task); + ieee80211_draintask(ic, &sc->sc_radiooff_task); + iwn_stop(sc); taskqueue_drain_all(sc->sc_tq); @@ -1389,11 +1415,9 @@ iwn_detach(device_t dev) callout_drain(&sc->watchdog_to); callout_drain(&sc->calib_to); - ieee80211_ifdetach(&sc->sc_ic); + ieee80211_ifdetach(ic); } - mbufq_drain(&sc->sc_snd); - /* Uninstall interrupt handler. */ if (sc->irq != NULL) { bus_teardown_intr(dev, sc->irq, sc->sc_ih); @@ -1416,6 +1440,9 @@ iwn_detach(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), sc->mem); + if (ifp != NULL) + if_free(ifp); + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n", __func__); IWN_LOCK_DESTROY(sc); return 0; @@ -1434,8 +1461,9 @@ static int iwn_suspend(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = sc->sc_ifp->if_l2com; - ieee80211_suspend_all(&sc->sc_ic); + ieee80211_suspend_all(ic); return 0; } @@ -1443,11 +1471,12 @@ static int iwn_resume(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); - ieee80211_resume_all(&sc->sc_ic); + ieee80211_resume_all(ic); return 0; } @@ -2356,7 +2385,8 @@ iwn_eeprom_channel_flags(struct iwn_eeprom_chan *channel) static void iwn_read_eeprom_band(struct iwn_softc *sc, int n) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c; @@ -2415,7 +2445,8 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) static void iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c, *cent, *extc; @@ -2483,7 +2514,8 @@ iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) static void iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; iwn_read_prom_data(sc, addr, &sc->eeprom_channels[n], iwn_bands[n].nchan * sizeof (struct iwn_eeprom_chan)); @@ -2551,7 +2583,8 @@ static void iwn_read_eeprom_enhinfo(struct iwn_softc *sc) { struct iwn_eeprom_enhinfo enhinfo[35]; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_channel *c; uint16_t val, base; int8_t maxpwr; @@ -2934,7 +2967,8 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct iwn_rx_ring *ring = &sc->rxq; struct ieee80211_frame *wh; struct ieee80211_node *ni; @@ -2981,14 +3015,14 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) { DPRINTF(sc, IWN_DEBUG_RECV, "%s: RX flags error %x\n", __func__, flags); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } /* Discard frames that are too short. */ if (len < sizeof (struct ieee80211_frame_ack)) { DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too short: %d\n", __func__, len); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -2996,7 +3030,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, if (m1 == NULL) { DPRINTF(sc, IWN_DEBUG_ANY, "%s: no mbuf to restock ring\n", __func__); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } bus_dmamap_unload(ring->data_dmat, data->map); @@ -3019,7 +3053,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, ring->desc[ring->cur] = htole32(paddr >> 8); bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -3031,6 +3065,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ + m->m_pkthdr.rcvif = ifp; m->m_data = head; m->m_pkthdr.len = m->m_len = len; @@ -3124,6 +3159,7 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; + struct ifnet *ifp = sc->sc_ifp; struct iwn_node *wn; struct ieee80211_node *ni; struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1); @@ -3204,10 +3240,12 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap; for (i = 0; bitmap; i++) { if ((bitmap & 1) == 0) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); tx_err ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); tx_ok ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); @@ -3353,7 +3391,8 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; - 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 iwn_calib_state *calib = &sc->calib; struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); @@ -3526,6 +3565,7 @@ static void iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, uint8_t status) { + struct ifnet *ifp = sc->sc_ifp; struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; struct iwn_tx_data *data = &ring->data[desc->idx]; struct mbuf *m; @@ -3546,12 +3586,15 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, /* * Update rate control statistics for the node. */ - if (status & IWN_TX_FAIL) + if (status & IWN_TX_FAIL) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); - else + } else { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); + } /* * Channels marked for "radar" require traffic to be received @@ -3577,8 +3620,11 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, sc->sc_tx_timer = 0; if (--ring->queued < IWN_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); - if (sc->qfullmsk == 0) - iwn_start_locked(sc); + if (sc->qfullmsk == 0 && + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + iwn_start_locked(ifp); + } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); @@ -3623,6 +3669,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, int ackfailcnt, void *stat) { struct iwn_ops *ops = &sc->ops; + struct ifnet *ifp = sc->sc_ifp; struct iwn_tx_ring *ring = &sc->txq[qid]; struct iwn_tx_data *data; struct mbuf *m; @@ -3761,8 +3808,11 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, sc->sc_tx_timer = 0; if (ring->queued < IWN_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); - if (sc->qfullmsk == 0) - iwn_start_locked(sc); + if (sc->qfullmsk == 0 && + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + iwn_start_locked(ifp); + } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); @@ -3776,7 +3826,8 @@ static void iwn_notif_intr(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; - 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); uint16_t hw; @@ -3970,7 +4021,8 @@ iwn_wakeup_intr(struct iwn_softc *sc) static void iwn_rftoggle_intr(struct iwn_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp = IWN_READ(sc, IWN_GP_CNTRL); IWN_LOCK_ASSERT(sc); @@ -4049,6 +4101,7 @@ static void iwn_intr(void *arg) { struct iwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t r1, r2, tmp; IWN_LOCK(sc); @@ -4141,7 +4194,7 @@ iwn_intr(void *arg) done: /* Re-enable interrupts. */ - if (sc->sc_flags & IWN_FLAG_RUNNING) + if (ifp->if_flags & IFF_UP) IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); IWN_UNLOCK(sc); @@ -4625,7 +4678,9 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { struct iwn_ops *ops = &sc->ops; +// struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap = ni->ni_vap; +// struct ieee80211com *ic = ifp->if_l2com; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; @@ -4820,6 +4875,7 @@ static void iwn_xmit_task(void *arg0, int pending) { struct iwn_softc *sc = arg0; + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_node *ni; struct mbuf *m; int error; @@ -4851,9 +4907,8 @@ iwn_xmit_task(void *arg0, int pending) error = iwn_tx_data(sc, m, ni); if (error != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } } @@ -4866,12 +4921,13 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct iwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwn_softc *sc = ifp->if_softc; int error = 0; DPRINTF(sc, IWN_DEBUG_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__); - if ((sc->sc_flags & IWN_FLAG_RUNNING) == 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { ieee80211_free_node(ni); m_freem(m); return ENETDOWN; @@ -4886,9 +4942,8 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if (sc->sc_beacon_wait) { if (iwn_xmit_queue_enqueue(sc, m) != 0) { m_freem(m); - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); IWN_UNLOCK(sc); return (ENOBUFS); } @@ -4913,6 +4968,7 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if (error != 0) { /* NB: m is reclaimed on tx failure */ ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } else sc->sc_tx_timer = 5; @@ -4923,32 +4979,20 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return error; } -static int -iwn_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +iwn_start(struct ifnet *ifp) { - struct iwn_softc *sc; - int error; - - sc = ic->ic_softc; + struct iwn_softc *sc = ifp->if_softc; IWN_LOCK(sc); - if ((sc->sc_flags & IWN_FLAG_RUNNING) == 0) { - IWN_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - IWN_UNLOCK(sc); - return (error); - } - iwn_start_locked(sc); + iwn_start_locked(ifp); IWN_UNLOCK(sc); - return (0); } static void -iwn_start_locked(struct iwn_softc *sc) +iwn_start_locked(struct ifnet *ifp) { + struct iwn_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; @@ -4963,16 +5007,27 @@ iwn_start_locked(struct iwn_softc *sc) } DPRINTF(sc, IWN_DEBUG_XMIT, "%s: called\n", __func__); - while (sc->qfullmsk == 0 && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) + return; + + for (;;) { + if (sc->qfullmsk != 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (iwn_tx_data(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } else sc->sc_tx_timer = 5; } + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__); } @@ -4980,11 +5035,12 @@ static void iwn_watchdog(void *arg) { struct iwn_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IWN_LOCK_ASSERT(sc); - KASSERT(sc->sc_flags & IWN_FLAG_RUNNING, ("not running")); + KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -4999,13 +5055,41 @@ iwn_watchdog(void *arg) } static int -iwn_ioctl(struct ieee80211com *ic, u_long cmd, void *data) +iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct ifreq *ifr = data; - struct iwn_softc *sc = ic->ic_softc; - int error = 0; - + struct iwn_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0, stop = 0; + switch (cmd) { + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + case SIOCSIFFLAGS: + IWN_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + iwn_init_locked(sc); + if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL) + startall = 1; + else + stop = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + iwn_stop_locked(sc); + } + IWN_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); + else if (vap != NULL && stop) + ieee80211_stop(vap); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; case SIOCGIWNSTATS: IWN_LOCK(sc); /* XXX validate permissions/memory/etc? */ @@ -5019,35 +5103,10 @@ iwn_ioctl(struct ieee80211com *ic, u_long cmd, void *data) IWN_UNLOCK(sc); break; default: - error = ENOTTY; + error = EINVAL; break; } - return (error); -} - -static void -iwn_parent(struct ieee80211com *ic) -{ - struct iwn_softc *sc = ic->ic_softc; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - int startall = 0, stop = 0; - - IWN_LOCK(sc); - if (ic->ic_nrunning > 0) { - if (!(sc->sc_flags & IWN_FLAG_RUNNING)) { - iwn_init_locked(sc); - if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL) - startall = 1; - else - stop = 1; - } - } else if (sc->sc_flags & IWN_FLAG_RUNNING) - iwn_stop_locked(sc); - IWN_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); - else if (vap != NULL && stop) - ieee80211_stop(vap); + return error; } /* @@ -5281,7 +5340,8 @@ static int iwn_add_broadcast_node(struct iwn_softc *sc, int async) { struct iwn_ops *ops = &sc->ops; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct iwn_node_info node; struct iwn_cmd_link_quality linkq; uint8_t txant; @@ -5292,7 +5352,7 @@ iwn_add_broadcast_node(struct iwn_softc *sc, int async) sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; memset(&node, 0, sizeof node); - IEEE80211_ADDR_COPY(node.macaddr, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); node.id = sc->broadcast_id; DPRINTF(sc, IWN_DEBUG_RESET, "%s: adding broadcast node\n", __func__); if ((error = ops->add_node(sc, &node, async)) != 0) @@ -5441,7 +5501,8 @@ iwn_set_timing(struct iwn_softc *sc, struct ieee80211_node *ni) static void iwn4965_power_calibration(struct iwn_softc *sc, int temp) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -5811,7 +5872,8 @@ iwn_collect_noise(struct iwn_softc *sc, { struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t val; int i; @@ -6444,8 +6506,9 @@ iwn5000_runtime_calib(struct iwn_softc *sc) static uint32_t iwn_get_rxon_ht_flags(struct iwn_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; uint32_t htflags = 0; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; if (! IEEE80211_IS_CHAN_HT(c)) return (0); @@ -6472,9 +6535,8 @@ static int iwn_config(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - const uint8_t *macaddr; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t txmask; uint16_t rxchain; int error; @@ -6556,9 +6618,8 @@ iwn_config(struct iwn_softc *sc) /* Set mode, channel, RX filter and enable RX. */ sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; memset(sc->rxon, 0, sizeof (struct iwn_rxon)); - macaddr = vap ? vap->iv_myaddr : ic->ic_macaddr; - IEEE80211_ADDR_COPY(sc->rxon->myaddr, macaddr); - IEEE80211_ADDR_COPY(sc->rxon->wlap, macaddr); + IEEE80211_ADDR_COPY(sc->rxon->myaddr, IF_LLADDR(ifp)); + IEEE80211_ADDR_COPY(sc->rxon->wlap, IF_LLADDR(ifp)); sc->rxon->chan = ieee80211_chan2ieee(ic, ic->ic_curchan); sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) @@ -6671,7 +6732,7 @@ iwn_get_active_dwell_time(struct iwn_softc *sc, static uint16_t iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = NULL; int bintval = 0; @@ -6719,7 +6780,8 @@ static int iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, struct ieee80211_scan_state *ss, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; struct iwn_scan_hdr *hdr; struct iwn_cmd_data *tx; @@ -6857,9 +6919,9 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; - IEEE80211_ADDR_COPY(wh->i_addr1, vap->iv_ifp->if_broadcastaddr); - IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(vap->iv_ifp)); - IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_ifp->if_broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp)); + IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ @@ -6978,7 +7040,8 @@ static int iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) { struct iwn_ops *ops = &sc->ops; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; int error; @@ -7050,7 +7113,8 @@ static int iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) { struct iwn_ops *ops = &sc->ops; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; struct iwn_node_info node; int error; @@ -8621,7 +8685,8 @@ static void iwn_radio_on(void *arg0, int pending) { struct iwn_softc *sc = arg0; - 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); DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -8636,7 +8701,8 @@ static void iwn_radio_off(void *arg0, int pending) { struct iwn_softc *sc = arg0; - 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); DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -8656,7 +8722,8 @@ static void iwn_panicked(void *arg0, int pending) { struct iwn_softc *sc = arg0; - 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); int error; @@ -8684,7 +8751,7 @@ iwn_panicked(void *arg0, int pending) } /* Only run start once the NIC is in a useful state, like associated */ - iwn_start_locked(sc); + iwn_start_locked(sc->sc_ifp); IWN_UNLOCK(sc); } @@ -8692,14 +8759,13 @@ iwn_panicked(void *arg0, int pending) static void iwn_init_locked(struct iwn_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); IWN_LOCK_ASSERT(sc); - sc->sc_flags |= IWN_FLAG_RUNNING; - if ((error = iwn_hw_prepare(sc)) != 0) { device_printf(sc->sc_dev, "%s: hardware not ready, error %d\n", __func__, error); @@ -8747,33 +8813,38 @@ iwn_init_locked(struct iwn_softc *sc) goto fail; } + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return; -fail: - sc->sc_flags &= ~IWN_FLAG_RUNNING; - iwn_stop_locked(sc); +fail: iwn_stop_locked(sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); } static void -iwn_init(struct iwn_softc *sc) +iwn_init(void *arg) { + struct iwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IWN_LOCK(sc); iwn_init_locked(sc); IWN_UNLOCK(sc); - if (sc->sc_flags & IWN_FLAG_RUNNING) - ieee80211_start_all(&sc->sc_ic); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); } static void iwn_stop_locked(struct iwn_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; IWN_LOCK_ASSERT(sc); @@ -8781,7 +8852,7 @@ iwn_stop_locked(struct iwn_softc *sc) sc->sc_tx_timer = 0; callout_stop(&sc->watchdog_to); callout_stop(&sc->calib_to); - sc->sc_flags &= ~IWN_FLAG_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* Power OFF hardware. */ iwn_hw_stop(sc); @@ -8801,7 +8872,8 @@ iwn_stop(struct iwn_softc *sc) static void iwn_scan_start(struct ieee80211com *ic) { - struct iwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwn_softc *sc = ifp->if_softc; IWN_LOCK(sc); /* make the link LED blink while we're scanning */ @@ -8815,7 +8887,8 @@ iwn_scan_start(struct ieee80211com *ic) static void iwn_scan_end(struct ieee80211com *ic) { - struct iwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwn_softc *sc = ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); IWN_LOCK(sc); @@ -8833,7 +8906,8 @@ static void iwn_set_channel(struct ieee80211com *ic) { const struct ieee80211_channel *c = ic->ic_curchan; - struct iwn_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct iwn_softc *sc = ifp->if_softc; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -8890,7 +8964,8 @@ static void iwn_hw_reset(void *arg0, int pending) { struct iwn_softc *sc = arg0; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); diff --git a/sys/dev/iwn/if_iwnvar.h b/sys/dev/iwn/if_iwnvar.h index ed275bf..9366fc2 100644 --- a/sys/dev/iwn/if_iwnvar.h +++ b/sys/dev/iwn/if_iwnvar.h @@ -228,16 +228,18 @@ struct iwn_vap { enum ieee80211_state, int); int ctx; int beacon_int; + uint8_t macaddr[IEEE80211_ADDR_LEN]; }; #define IWN_VAP(_vap) ((struct iwn_vap *)(_vap)) struct iwn_softc { device_t sc_dev; + + struct ifnet *sc_ifp; int sc_debug; + struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mbufq sc_snd; u_int sc_flags; #define IWN_FLAG_HAS_OTPROM (1 << 1) @@ -249,7 +251,6 @@ struct iwn_softc { #define IWN_FLAG_ADV_BTCOEX (1 << 8) #define IWN_FLAG_PAN_SUPPORT (1 << 9) #define IWN_FLAG_BTCOEX (1 << 10) -#define IWN_FLAG_RUNNING (1 << 11) uint8_t hw_type; /* subdevice_id used to adjust configuration */ @@ -319,6 +320,7 @@ struct iwn_softc { struct iwn_calib_state calib; int last_calib_ticks; struct callout watchdog_to; + struct callout ct_kill_exit_to; struct iwn_fw_info fw; struct iwn_calib_info calibcmd[IWN5000_PHY_CALIB_MAX_RESULT]; uint32_t errptr; diff --git a/sys/dev/malo/if_malo.c b/sys/dev/malo/if_malo.c index 2790fdc..7418379 100644 --- a/sys/dev/malo/if_malo.c +++ b/sys/dev/malo/if_malo.c @@ -102,9 +102,13 @@ enum { (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_BEACON)) #define IFF_DUMPPKTS_RECV(sc, wh) \ (((sc->malo_debug & MALO_DEBUG_RECV) && \ - ((sc->malo_debug & MALO_DEBUG_RECV_ALL) || !IS_BEACON(wh)))) + ((sc->malo_debug & MALO_DEBUG_RECV_ALL) || !IS_BEACON(wh))) || \ + (sc->malo_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == \ + (IFF_DEBUG|IFF_LINK2)) #define IFF_DUMPPKTS_XMIT(sc) \ - (sc->malo_debug & MALO_DEBUG_XMIT) + ((sc->malo_debug & MALO_DEBUG_XMIT) || \ + (sc->malo_ifp->if_flags & (IFF_DEBUG | IFF_LINK2)) == \ + (IFF_DEBUG | IFF_LINK2)) #define DPRINTF(sc, m, fmt, ...) do { \ if (sc->malo_debug & (m)) \ printf(fmt, __VA_ARGS__); \ @@ -126,10 +130,9 @@ static int malo_dma_setup(struct malo_softc *); static int malo_setup_hwdma(struct malo_softc *); static void malo_txq_init(struct malo_softc *, struct malo_txq *, int); static void malo_tx_cleanupq(struct malo_softc *, struct malo_txq *); -static void malo_parent(struct ieee80211com *); -static int malo_transmit(struct ieee80211com *, struct mbuf *); -static void malo_start(struct malo_softc *); +static void malo_start(struct ifnet *); static void malo_watchdog(void *); +static int malo_ioctl(struct ifnet *, u_long, caddr_t); static void malo_updateslot(struct ieee80211com *); static int malo_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void malo_scan_start(struct ieee80211com *); @@ -140,7 +143,7 @@ static int malo_raw_xmit(struct ieee80211_node *, struct mbuf *, static void malo_sysctlattach(struct malo_softc *); static void malo_announce(struct malo_softc *); static void malo_dma_cleanup(struct malo_softc *); -static void malo_stop(struct malo_softc *); +static void malo_stop_locked(struct ifnet *, int); static int malo_chan_set(struct malo_softc *, struct ieee80211_channel *); static int malo_mode_init(struct malo_softc *); static void malo_tx_proc(void *, int); @@ -170,19 +173,30 @@ malo_bar0_write4(struct malo_softc *sc, bus_size_t off, uint32_t val) int malo_attach(uint16_t devid, struct malo_softc *sc) { - struct ieee80211com *ic = &sc->malo_ic; - struct malo_hal *mh; int error; + struct ieee80211com *ic; + struct ifnet *ifp; + struct malo_hal *mh; uint8_t bands; + ifp = sc->malo_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->malo_dev, "can not if_alloc()\n"); + return ENOSPC; + } + ic = ifp->if_l2com; + MALO_LOCK_INIT(sc); callout_init_mtx(&sc->malo_watchdog_timer, &sc->malo_mtx, 0); - mbufq_init(&sc->malo_snd, ifqmaxlen); + + /* set these up early for if_printf use */ + if_initname(ifp, device_get_name(sc->malo_dev), + device_get_unit(sc->malo_dev)); mh = malo_hal_attach(sc->malo_dev, devid, sc->malo_io1h, sc->malo_io1t, sc->malo_dmat); if (mh == NULL) { - device_printf(sc->malo_dev, "unable to attach HAL\n"); + if_printf(ifp, "unable to attach HAL\n"); error = EIO; goto bad; } @@ -195,13 +209,13 @@ malo_attach(uint16_t devid, struct malo_softc *sc) */ error = malo_hal_fwload(mh, "malo8335-h", "malo8335-m"); if (error != 0) { - device_printf(sc->malo_dev, "unable to setup firmware\n"); + if_printf(ifp, "unable to setup firmware\n"); goto bad1; } /* XXX gethwspecs() extracts correct informations? not maybe! */ error = malo_hal_gethwspecs(mh, &sc->malo_hwspecs); if (error != 0) { - device_printf(sc->malo_dev, "unable to fetch h/w specs\n"); + if_printf(ifp, "unable to fetch h/w specs\n"); goto bad1; } @@ -237,8 +251,7 @@ malo_attach(uint16_t devid, struct malo_softc *sc) */ error = malo_dma_setup(sc); if (error != 0) { - device_printf(sc->malo_dev, - "failed to setup descriptors: %d\n", error); + if_printf(ifp, "failed to setup descriptors: %d\n", error); goto bad1; } error = malo_setup_hwdma(sc); /* push to firmware */ @@ -248,11 +261,21 @@ malo_attach(uint16_t devid, struct malo_softc *sc) sc->malo_tq = taskqueue_create_fast("malo_taskq", M_NOWAIT, taskqueue_thread_enqueue, &sc->malo_tq); taskqueue_start_threads(&sc->malo_tq, 1, PI_NET, - "%s taskq", device_get_nameunit(sc->malo_dev)); + "%s taskq", ifp->if_xname); TASK_INIT(&sc->malo_rxtask, 0, malo_rx_proc, sc); TASK_INIT(&sc->malo_txtask, 0, malo_tx_proc, sc); + ifp->if_softc = sc; + ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_start = malo_start; + ifp->if_ioctl = malo_ioctl; + ifp->if_init = malo_init; + 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(sc->malo_dev); /* XXX not right but it's not used anywhere important */ @@ -267,7 +290,6 @@ malo_attach(uint16_t devid, struct malo_softc *sc) | IEEE80211_C_TXPMGT /* capable of txpow mgt */ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ ; - IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->malo_hwspecs.macaddr); /* * Transmit requires space in the packet for a special format transmit @@ -279,17 +301,16 @@ malo_attach(uint16_t devid, struct malo_softc *sc) sizeof(struct ieee80211_frame); /* call MI attach routine. */ - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->malo_hwspecs.macaddr); /* override default methods */ ic->ic_vap_create = malo_vap_create; ic->ic_vap_delete = malo_vap_delete; ic->ic_raw_xmit = malo_raw_xmit; ic->ic_updateslot = malo_updateslot; + ic->ic_scan_start = malo_scan_start; ic->ic_scan_end = malo_scan_end; ic->ic_set_channel = malo_set_channel; - ic->ic_parent = malo_parent; - ic->ic_transmit = malo_transmit; sc->malo_invalid = 0; /* ready to go, enable int handling */ @@ -314,6 +335,7 @@ bad2: bad1: malo_hal_detach(mh); bad: + if_free(ifp); sc->malo_invalid = 1; return error; @@ -325,12 +347,12 @@ malo_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct malo_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; struct malo_vap *mvp; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) { - device_printf(sc->malo_dev, "multiple vaps not supported\n"); + if_printf(ifp, "multiple vaps not supported\n"); return NULL; } switch (opmode) { @@ -341,13 +363,18 @@ malo_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_MONITOR: break; default: - device_printf(sc->malo_dev, "%s mode not supported\n", + if_printf(ifp, "%s mode not supported\n", ieee80211_opmode_name[opmode]); return NULL; /* unsupported */ } - mvp = malloc(sizeof(struct malo_vap), M_80211_VAP, M_WAITOK | M_ZERO); + mvp = (struct malo_vap *) malloc(sizeof(struct malo_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (mvp == NULL) { + if_printf(ifp, "cannot allocate vap state block\n"); + return NULL; + } vap = &mvp->malo_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override state transition machine */ mvp->malo_newstate = vap->iv_newstate; @@ -355,7 +382,7 @@ malo_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_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -434,6 +461,7 @@ malo_desc_setup(struct malo_softc *sc, const char *name, int nbuf, size_t bufsize, int ndesc, size_t descsize) { int error; + struct ifnet *ifp = sc->malo_ifp; uint8_t *ds; DPRINTF(sc, MALO_DEBUG_RESET, @@ -460,8 +488,7 @@ malo_desc_setup(struct malo_softc *sc, const char *name, NULL, /* lockarg */ &dd->dd_dmat); if (error != 0) { - device_printf(sc->malo_dev, "cannot allocate %s DMA tag\n", - dd->dd_name); + if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name); return error; } @@ -469,8 +496,7 @@ malo_desc_setup(struct malo_softc *sc, const char *name, error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dd->dd_dmamap); if (error != 0) { - device_printf(sc->malo_dev, - "unable to alloc memory for %u %s descriptors, " + if_printf(ifp, "unable to alloc memory for %u %s descriptors, " "error %u\n", nbuf * ndesc, dd->dd_name, error); goto fail1; } @@ -479,8 +505,7 @@ malo_desc_setup(struct malo_softc *sc, const char *name, dd->dd_desc, dd->dd_desc_len, malo_load_cb, &dd->dd_desc_paddr, BUS_DMA_NOWAIT); if (error != 0) { - device_printf(sc->malo_dev, - "unable to map %s descriptors, error %u\n", + if_printf(ifp, "unable to map %s descriptors, error %u\n", dd->dd_name, error); goto fail2; } @@ -507,6 +532,7 @@ fail1: static int malo_rxdma_setup(struct malo_softc *sc) { + struct ifnet *ifp = sc->malo_ifp; int error, bsize, i; struct malo_rxbuf *bf; struct malo_rxdesc *ds; @@ -523,8 +549,7 @@ malo_rxdma_setup(struct malo_softc *sc) bsize = malo_rxbuf * sizeof(struct malo_rxbuf); bf = malloc(bsize, M_MALODEV, M_NOWAIT | M_ZERO); if (bf == NULL) { - device_printf(sc->malo_dev, - "malloc of %u rx buffers failed\n", bsize); + if_printf(ifp, "malloc of %u rx buffers failed\n", bsize); return error; } sc->malo_rxdma.dd_bufptr = bf; @@ -537,9 +562,8 @@ malo_rxdma_setup(struct malo_softc *sc) error = bus_dmamap_create(sc->malo_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap); if (error != 0) { - device_printf(sc->malo_dev, - "%s: unable to dmamap for rx buffer, error %d\n", - __func__, error); + if_printf(ifp, "%s: unable to dmamap for rx buffer, " + "error %d\n", __func__, error); return error; } /* NB: tail is intentional to preserve descriptor order */ @@ -551,6 +575,7 @@ malo_rxdma_setup(struct malo_softc *sc) static int malo_txdma_setup(struct malo_softc *sc, struct malo_txq *txq) { + struct ifnet *ifp = sc->malo_ifp; int error, bsize, i; struct malo_txbuf *bf; struct malo_txdesc *ds; @@ -565,7 +590,7 @@ malo_txdma_setup(struct malo_softc *sc, struct malo_txq *txq) bsize = malo_txbuf * sizeof(struct malo_txbuf); bf = malloc(bsize, M_MALODEV, M_NOWAIT | M_ZERO); if (bf == NULL) { - device_printf(sc->malo_dev, "malloc of %u tx buffers failed\n", + if_printf(ifp, "malloc of %u tx buffers failed\n", malo_txbuf); return ENOMEM; } @@ -580,8 +605,7 @@ malo_txdma_setup(struct malo_softc *sc, struct malo_txq *txq) error = bus_dmamap_create(sc->malo_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap); if (error != 0) { - device_printf(sc->malo_dev, - "unable to create dmamap for tx " + if_printf(ifp, "unable to create dmamap for tx " "buffer %u, error %u\n", i, error); return error; } @@ -980,19 +1004,33 @@ malo_tx_processq(struct malo_softc *sc, struct malo_txq *txq) if (status & MALO_TXD_STATUS_FAILED_AGING) sc->malo_stats.mst_tx_aging++; } - /* XXX strip fw len in case header inspected */ - m_adj(bf->bf_m, sizeof(uint16_t)); - ieee80211_tx_complete(ni, bf->bf_m, - (status & MALO_TXD_STATUS_OK) == 0); - } else - m_freem(bf->bf_m); - + /* + * Do any tx complete callback. Note this must + * be done before releasing the node reference. + * XXX no way to figure out if frame was ACK'd + */ + if (bf->bf_m->m_flags & M_TXCB) { + /* XXX strip fw len in case header inspected */ + m_adj(bf->bf_m, sizeof(uint16_t)); + ieee80211_process_callback(ni, bf->bf_m, + (status & MALO_TXD_STATUS_OK) == 0); + } + /* + * Reclaim reference to node. + * + * NB: the node may be reclaimed here if, for example + * this is a DEAUTH message that was sent and the + * node was timed out due to inactivity. + */ + ieee80211_free_node(ni); + } ds->status = htole32(MALO_TXD_STATUS_IDLE); ds->pktlen = htole32(0); bus_dmamap_sync(sc->malo_dmat, bf->bf_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->malo_dmat, bf->bf_dmamap); + m_freem(bf->bf_m); bf->bf_m = NULL; bf->bf_node = NULL; @@ -1011,23 +1049,23 @@ static void malo_tx_proc(void *arg, int npending) { struct malo_softc *sc = arg; + struct ifnet *ifp = sc->malo_ifp; int i, nreaped; /* * Process each active queue. */ nreaped = 0; - MALO_LOCK(sc); for (i = 0; i < MALO_NUM_TX_QUEUES; i++) { if (!STAILQ_EMPTY(&sc->malo_txq[i].active)) nreaped += malo_tx_processq(sc, &sc->malo_txq[i]); } if (nreaped != 0) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->malo_timer = 0; - malo_start(sc); + malo_start(ifp); } - MALO_UNLOCK(sc); } static int @@ -1041,7 +1079,8 @@ malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, int error, ismcast, iswep; int copyhdrlen, hdrlen, pktlen; struct ieee80211_frame *wh; - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct malo_txdesc *ds; struct malo_txrec *tr; @@ -1186,7 +1225,7 @@ malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, ds->txpriority = txq->qnum; break; default: - device_printf(sc->malo_dev, "bogus frame type 0x%x (%s)\n", + if_printf(ifp, "bogus frame type 0x%x (%s)\n", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); /* XXX statistic */ m_freem(m0); @@ -1207,52 +1246,37 @@ malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, STAILQ_INSERT_TAIL(&txq->active, bf, bf_list); MALO_TXDESC_SYNC(txq, ds, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); sc->malo_timer = 5; MALO_TXQ_UNLOCK(txq); return 0; #undef IEEE80211_DIR_DSTODS } -static int -malo_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct malo_softc *sc = ic->ic_softc; - int error; - - MALO_LOCK(sc); - if (!sc->malo_running) { - MALO_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->malo_snd, m); - if (error) { - MALO_UNLOCK(sc); - return (error); - } - malo_start(sc); - MALO_UNLOCK(sc); - return (0); -} - static void -malo_start(struct malo_softc *sc) +malo_start(struct ifnet *ifp) { + struct malo_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct malo_txq *txq = &sc->malo_txq[0]; struct malo_txbuf *bf = NULL; struct mbuf *m; int nqueued = 0; - MALO_LOCK_ASSERT(sc); - - if (!sc->malo_running || sc->malo_invalid) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->malo_invalid) return; - while ((m = mbufq_dequeue(&sc->malo_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; bf = malo_getbuf(sc, txq); if (bf == NULL) { - mbufq_prepend(&sc->malo_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); + + /* XXX blocks other traffic */ + ifp->if_drv_flags |= IFF_DRV_OACTIVE; sc->malo_stats.mst_tx_qstop++; break; } @@ -1260,8 +1284,7 @@ malo_start(struct malo_softc *sc) * Pass the frame to the h/w for transmission. */ if (malo_tx_start(sc, ni, bf, m)) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (bf != NULL) { bf->bf_m = NULL; bf->bf_node = NULL; @@ -1305,18 +1328,21 @@ malo_start(struct malo_softc *sc) static void malo_watchdog(void *arg) { - struct malo_softc *sc = arg; + struct malo_softc *sc; + struct ifnet *ifp; + sc = arg; callout_reset(&sc->malo_watchdog_timer, hz, malo_watchdog, sc); if (sc->malo_timer == 0 || --sc->malo_timer > 0) return; - if (sc->malo_running && !sc->malo_invalid) { - device_printf(sc->malo_dev, "watchdog timeout\n"); + ifp = sc->malo_ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && !sc->malo_invalid) { + if_printf(ifp, "watchdog timeout\n"); /* XXX no way to reset h/w. now */ - counter_u64_add(sc->malo_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); sc->malo_stats.mst_watchdog++; } } @@ -1325,7 +1351,8 @@ static int malo_hal_reset(struct malo_softc *sc) { static int first = 0; - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct malo_hal *mh = sc->malo_mh; if (first == 0) { @@ -1365,7 +1392,7 @@ malo_getrxmbuf(struct malo_softc *sc, struct malo_rxbuf *bf) mtod(m, caddr_t), MJUMPAGESIZE, malo_load_cb, &paddr, BUS_DMA_NOWAIT); if (error != 0) { - device_printf(sc->malo_dev, + if_printf(sc->malo_ifp, "%s: bus_dmamap_load failed, error %d\n", __func__, error); m_freem(m); return NULL; @@ -1456,23 +1483,26 @@ malo_startrecv(struct malo_softc *sc) static void malo_init_locked(struct malo_softc *sc) { + struct ifnet *ifp = sc->malo_ifp; struct malo_hal *mh = sc->malo_mh; int error; + DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags 0x%x\n", + __func__, ifp->if_flags); + MALO_LOCK_ASSERT(sc); /* * Stop anything previously setup. This is safe whether this is * the first time through or not. */ - malo_stop(sc); + malo_stop_locked(ifp, 0); /* * Push state to the firmware. */ if (!malo_hal_reset(sc)) { - device_printf(sc->malo_dev, - "%s: unable to reset hardware\n", __func__); + if_printf(ifp, "%s: unable to reset hardware\n", __func__); return; } @@ -1481,8 +1511,7 @@ malo_init_locked(struct malo_softc *sc) */ error = malo_startrecv(sc); if (error != 0) { - device_printf(sc->malo_dev, - "%s: unable to start recv logic, error %d\n", + if_printf(ifp, "%s: unable to start recv logic, error %d\n", __func__, error); return; } @@ -1499,7 +1528,7 @@ malo_init_locked(struct malo_softc *sc) | MALO_A2HRIC_BIT_RADAR_DETECT | MALO_A2HRIC_BIT_CHAN_SWITCH; - sc->malo_running = 1; + ifp->if_drv_flags |= IFF_DRV_RUNNING; malo_hal_intrset(mh, sc->malo_imask); callout_reset(&sc->malo_watchdog_timer, hz, malo_watchdog, sc); } @@ -1508,13 +1537,18 @@ static void malo_init(void *arg) { struct malo_softc *sc = (struct malo_softc *) arg; - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; + DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags 0x%x\n", + __func__, ifp->if_flags); + MALO_LOCK(sc); malo_init_locked(sc); + MALO_UNLOCK(sc); - if (sc->malo_running) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); /* start all vap's */ } @@ -1524,8 +1558,9 @@ malo_init(void *arg) static void malo_setmcastfilter(struct malo_softc *sc) { - struct ieee80211com *ic = &sc->malo_ic; - struct ieee80211vap *vap; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ifmultiaddr *ifma; uint8_t macs[IEEE80211_ADDR_LEN * MALO_HAL_MCAST_MAX]; uint8_t *mp; int nmc; @@ -1533,32 +1568,26 @@ malo_setmcastfilter(struct malo_softc *sc) mp = macs; nmc = 0; - if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_allmulti > 0 || - ic->ic_promisc > 0) + if (ic->ic_opmode == IEEE80211_M_MONITOR || + (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) goto all; + + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - struct ifnet *ifp; - struct ifmultiaddr *ifma; - - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (nmc == MALO_HAL_MCAST_MAX) { - ifp->if_flags |= IFF_ALLMULTI; - if_maddr_runlock(ifp); - goto all; - } - IEEE80211_ADDR_COPY(mp, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - - mp += IEEE80211_ADDR_LEN, nmc++; + if (nmc == MALO_HAL_MCAST_MAX) { + ifp->if_flags |= IFF_ALLMULTI; + if_maddr_runlock(ifp); + goto all; } - if_maddr_runlock(ifp); + IEEE80211_ADDR_COPY(mp, + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + + mp += IEEE80211_ADDR_LEN, nmc++; } + if_maddr_runlock(ifp); malo_hal_setmcast(sc->malo_mh, nmc, macs); @@ -1573,7 +1602,8 @@ all: static int malo_mode_init(struct malo_softc *sc) { - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct malo_hal *mh = sc->malo_mh; /* @@ -1582,7 +1612,7 @@ malo_mode_init(struct malo_softc *sc) * identify internal requests (from the bridge) * versus external requests such as for tcpdump. */ - malo_hal_setpromisc(mh, ic->ic_promisc > 0 && + malo_hal_setpromisc(mh, (ifp->if_flags & IFF_PROMISC) && ic->ic_opmode != IEEE80211_M_HOSTAP); malo_setmcastfilter(sc); @@ -1611,7 +1641,8 @@ malo_tx_draintxq(struct malo_softc *sc, struct malo_txq *txq) MALO_TXQ_UNLOCK(txq); #ifdef MALO_DEBUG if (sc->malo_debug & MALO_DEBUG_RESET) { - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct malo_txrec *tr = mtod(bf->bf_m, const struct malo_txrec *); malo_printtxbuf(bf, txq->qnum, ix); @@ -1639,17 +1670,18 @@ malo_tx_draintxq(struct malo_softc *sc, struct malo_txq *txq) } static void -malo_stop(struct malo_softc *sc) +malo_stop_locked(struct ifnet *ifp, int disable) { + struct malo_softc *sc = ifp->if_softc; struct malo_hal *mh = sc->malo_mh; int i; - DPRINTF(sc, MALO_DEBUG_ANY, "%s: invalid %u running %u\n", - __func__, sc->malo_invalid, sc->malo_running); + DPRINTF(sc, MALO_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", + __func__, sc->malo_invalid, ifp->if_flags); MALO_LOCK_ASSERT(sc); - if (!sc->malo_running) + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) return; /* @@ -1661,10 +1693,10 @@ malo_stop(struct malo_softc *sc) * Note that some of this work is not possible if the hardware * is gone (invalid). */ - sc->malo_running = 0; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; callout_stop(&sc->malo_watchdog_timer); sc->malo_timer = 0; - /* disable interrupt. */ + /* diable interrupt. */ malo_hal_intrset(mh, 0); /* turn off the radio. */ malo_hal_setradio(mh, 0, MHP_AUTO_PREAMBLE); @@ -1674,38 +1706,57 @@ malo_stop(struct malo_softc *sc) malo_tx_draintxq(sc, &sc->malo_txq[i]); } -static void -malo_parent(struct ieee80211com *ic) +static int +malo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct malo_softc *sc = ic->ic_softc; - int startall = 0; +#define MALO_IS_RUNNING(ifp) \ + ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + struct malo_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; MALO_LOCK(sc); - if (ic->ic_nrunning > 0) { - /* - * Beware of being called during attach/detach - * to reset promiscuous mode. In that case we - * will still be marked UP but not RUNNING. - * However trying to re-init the interface - * is the wrong thing to do as we've already - * torn down much of our state. There's - * probably a better way to deal with this. - */ - if (!sc->malo_running && !sc->malo_invalid) { - malo_init(sc); - startall = 1; - } - /* - * To avoid rescanning another access point, - * do not call malo_init() here. Instead, - * only reflect promisc mode settings. - */ - malo_mode_init(sc); - } else if (sc->malo_running) - malo_stop(sc); + switch (cmd) { + case SIOCSIFFLAGS: + if (MALO_IS_RUNNING(ifp)) { + /* + * To avoid rescanning another access point, + * do not call malo_init() here. Instead, + * only reflect promisc mode settings. + */ + malo_mode_init(sc); + } else if (ifp->if_flags & IFF_UP) { + /* + * Beware of being called during attach/detach + * to reset promiscuous mode. In that case we + * will still be marked UP but not RUNNING. + * However trying to re-init the interface + * is the wrong thing to do as we've already + * torn down much of our state. There's + * probably a better way to deal with this. + */ + if (!sc->malo_invalid) { + malo_init_locked(sc); + startall = 1; + } + } else + malo_stop_locked(ifp, 1); + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + default: + error = ether_ioctl(ifp, cmd, data); + break; + } MALO_UNLOCK(sc); + if (startall) ieee80211_start_all(ic); + return error; +#undef MALO_IS_RUNNING } /* @@ -1722,7 +1773,7 @@ malo_updateslot(struct ieee80211com *ic) int error; /* NB: can be called early; suppress needless cmds */ - if (!sc->malo_running) + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; DPRINTF(sc, MALO_DEBUG_RESET, @@ -1744,7 +1795,7 @@ static int malo_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; - struct malo_softc *sc = ic->ic_softc; + struct malo_softc *sc = ic->ic_ifp->if_softc; struct malo_hal *mh = sc->malo_mh; int error; @@ -1788,11 +1839,12 @@ malo_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct malo_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct malo_softc *sc = ifp->if_softc; struct malo_txbuf *bf; struct malo_txq *txq; - if (!sc->malo_running || sc->malo_invalid) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->malo_invalid) { ieee80211_free_node(ni); m_freem(m); return ENETDOWN; @@ -1807,6 +1859,8 @@ malo_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, txq = &sc->malo_txq[0]; bf = malo_getbuf(sc, txq); if (bf == NULL) { + /* XXX blocks other traffic */ + ifp->if_drv_flags |= IFF_DRV_OACTIVE; ieee80211_free_node(ni); m_freem(m); return ENOBUFS; @@ -1816,6 +1870,7 @@ malo_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, * Pass the frame to the h/w for transmission. */ if (malo_tx_start(sc, ni, bf, m) != 0) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); bf->bf_m = NULL; bf->bf_node = NULL; MALO_TXQ_LOCK(txq); @@ -1860,9 +1915,9 @@ malo_sysctlattach(struct malo_softc *sc) static void malo_announce(struct malo_softc *sc) { + struct ifnet *ifp = sc->malo_ifp; - device_printf(sc->malo_dev, - "versions [hw %d fw %d.%d.%d.%d] (regioncode %d)\n", + if_printf(ifp, "versions [hw %d fw %d.%d.%d.%d] (regioncode %d)\n", sc->malo_hwspecs.hwversion, (sc->malo_hwspecs.fw_releasenum >> 24) & 0xff, (sc->malo_hwspecs.fw_releasenum >> 16) & 0xff, @@ -1871,11 +1926,9 @@ malo_announce(struct malo_softc *sc) sc->malo_hwspecs.regioncode); if (bootverbose || malo_rxbuf != MALO_RXBUF) - device_printf(sc->malo_dev, - "using %u rx buffers\n", malo_rxbuf); + if_printf(ifp, "using %u rx buffers\n", malo_rxbuf); if (bootverbose || malo_txbuf != MALO_TXBUF) - device_printf(sc->malo_dev, - "using %u tx buffers\n", malo_txbuf); + if_printf(ifp, "using %u tx buffers\n", malo_txbuf); } /* @@ -1936,7 +1989,8 @@ malo_chan_set(struct malo_softc *sc, struct ieee80211_channel *chan) static void malo_scan_start(struct ieee80211com *ic) { - struct malo_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct malo_softc *sc = ifp->if_softc; DPRINTF(sc, MALO_DEBUG_STATE, "%s\n", __func__); } @@ -1944,7 +1998,8 @@ malo_scan_start(struct ieee80211com *ic) static void malo_scan_end(struct ieee80211com *ic) { - struct malo_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct malo_softc *sc = ifp->if_softc; DPRINTF(sc, MALO_DEBUG_STATE, "%s\n", __func__); } @@ -1952,7 +2007,8 @@ malo_scan_end(struct ieee80211com *ic) static void malo_set_channel(struct ieee80211com *ic) { - struct malo_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct malo_softc *sc = ifp->if_softc; (void) malo_chan_set(sc, ic->ic_curchan); } @@ -1964,7 +2020,8 @@ malo_rx_proc(void *arg, int npending) ((((const struct ieee80211_frame *)wh)->i_fc[1] & \ IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) struct malo_softc *sc = arg; - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct malo_rxbuf *bf; struct malo_rxdesc *ds; struct mbuf *m, *mnew; @@ -2021,7 +2078,7 @@ malo_rx_proc(void *arg, int npending) #endif status = ds->status; if (status & MALO_RXD_STATUS_DECRYPT_ERR_MASK) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto rx_next; } /* @@ -2060,7 +2117,7 @@ malo_rx_proc(void *arg, int npending) /* XXX don't need mbuf, just dma buffer */ mnew = malo_getrxmbuf(sc, bf); if (mnew == NULL) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto rx_next; } /* @@ -2071,6 +2128,7 @@ malo_rx_proc(void *arg, int npending) bf->bf_m = mnew; m->m_data += off - hdrlen; m->m_pkthdr.len = m->m_len = pktlen; + m->m_pkthdr.rcvif = ifp; /* * Piece 802.11 header together. @@ -2100,6 +2158,8 @@ malo_rx_proc(void *arg, int npending) len, ds->rate, rssi); } #endif + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + /* dispatch */ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); @@ -2117,11 +2177,22 @@ rx_next: malo_bar0_write4(sc, sc->malo_hwspecs.rxdesc_read, readptr); sc->malo_rxnext = bf; - if (mbufq_first(&sc->malo_snd) != NULL) - malo_start(sc); + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) + malo_start(ifp); #undef IEEE80211_DIR_DSTODS } +static void +malo_stop(struct ifnet *ifp, int disable) +{ + struct malo_softc *sc = ifp->if_softc; + + MALO_LOCK(sc); + malo_stop_locked(ifp, disable); + MALO_UNLOCK(sc); +} + /* * Reclaim all tx queue resources. */ @@ -2137,9 +2208,13 @@ malo_tx_cleanup(struct malo_softc *sc) int malo_detach(struct malo_softc *sc) { - struct ieee80211com *ic = &sc->malo_ic; + struct ifnet *ifp = sc->malo_ifp; + struct ieee80211com *ic = ifp->if_l2com; - malo_stop(sc); + DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); + + malo_stop(ifp, 1); if (sc->malo_tq != NULL) { taskqueue_drain(sc->malo_tq, &sc->malo_rxtask); @@ -2165,7 +2240,8 @@ malo_detach(struct malo_softc *sc) malo_dma_cleanup(sc); malo_tx_cleanup(sc); malo_hal_detach(sc->malo_mh); - mbufq_drain(&sc->malo_snd); + if_free(ifp); + MALO_LOCK_DESTROY(sc); return 0; @@ -2174,21 +2250,28 @@ malo_detach(struct malo_softc *sc) void malo_shutdown(struct malo_softc *sc) { - - malo_stop(sc); + malo_stop(sc->malo_ifp, 1); } void malo_suspend(struct malo_softc *sc) { + struct ifnet *ifp = sc->malo_ifp; - malo_stop(sc); + DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); + + malo_stop(ifp, 1); } void malo_resume(struct malo_softc *sc) { + struct ifnet *ifp = sc->malo_ifp; + + DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); - if (sc->malo_ic.ic_nrunning > 0) + if (ifp->if_flags & IFF_UP) malo_init(sc); } diff --git a/sys/dev/malo/if_malo.h b/sys/dev/malo/if_malo.h index 681e750..bac290c 100644 --- a/sys/dev/malo/if_malo.h +++ b/sys/dev/malo/if_malo.h @@ -520,9 +520,8 @@ struct malo_vap { #define MALO_VAP(vap) ((struct malo_vap *)(vap)) struct malo_softc { - struct ieee80211com malo_ic; - struct mbufq malo_snd; device_t malo_dev; + struct ifnet *malo_ifp; /* interface common */ struct mtx malo_mtx; /* master lock (recursive) */ struct taskqueue *malo_tq; /* private task queue */ @@ -532,10 +531,9 @@ struct malo_softc { bus_space_handle_t malo_io1h; /* BAR 1 */ bus_space_tag_t malo_io1t; - unsigned int malo_invalid: 1,/* disable hardware accesses */ - malo_recvsetup: 1, /* recv setup */ - malo_fixedrate: 1, /* use fixed tx rate */ - malo_running: 1; + unsigned int malo_invalid : 1,/* disable hardware accesses */ + malo_recvsetup : 1, /* recv setup */ + malo_fixedrate: 1; /* use fixed tx rate */ struct malo_hal *malo_mh; /* h/w access layer */ struct malo_hal_hwspec malo_hwspecs; /* h/w capabilities */ diff --git a/sys/dev/mwl/if_mwl.c b/sys/dev/mwl/if_mwl.c index be80e46..0997500 100644 --- a/sys/dev/mwl/if_mwl.c +++ b/sys/dev/mwl/if_mwl.c @@ -91,17 +91,17 @@ static struct ieee80211vap *mwl_vap_create(struct ieee80211com *, static void mwl_vap_delete(struct ieee80211vap *); static int mwl_setupdma(struct mwl_softc *); static int mwl_hal_reset(struct mwl_softc *sc); -static int mwl_init(struct mwl_softc *); -static void mwl_parent(struct ieee80211com *); +static int mwl_init_locked(struct mwl_softc *); +static void mwl_init(void *); +static void mwl_stop_locked(struct ifnet *, int); static int mwl_reset(struct ieee80211vap *, u_long); -static void mwl_stop(struct mwl_softc *); -static void mwl_start(struct mwl_softc *); -static int mwl_transmit(struct ieee80211com *, struct mbuf *); +static void mwl_stop(struct ifnet *, int); +static void mwl_start(struct ifnet *); static int mwl_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static int mwl_media_change(struct ifnet *); static void mwl_watchdog(void *); -static int mwl_ioctl(struct ieee80211com *, u_long, void *); +static int mwl_ioctl(struct ifnet *, u_long, caddr_t); static void mwl_radar_proc(void *, int); static void mwl_chanswitch_proc(void *, int); static void mwl_bawatchdog_proc(void *, int); @@ -229,11 +229,12 @@ enum { ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) == \ (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_BEACON)) #define IFF_DUMPPKTS_RECV(sc, wh) \ - ((sc->sc_debug & MWL_DEBUG_RECV) && \ - ((sc->sc_debug & MWL_DEBUG_RECV_ALL) || !IS_BEACON(wh))) + (((sc->sc_debug & MWL_DEBUG_RECV) && \ + ((sc->sc_debug & MWL_DEBUG_RECV_ALL) || !IS_BEACON(wh))) || \ + (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) #define IFF_DUMPPKTS_XMIT(sc) \ - (sc->sc_debug & MWL_DEBUG_XMIT) - + ((sc->sc_debug & MWL_DEBUG_XMIT) || \ + (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) #define DPRINTF(sc, m, fmt, ...) do { \ if (sc->sc_debug & (m)) \ printf(fmt, __VA_ARGS__); \ @@ -245,10 +246,16 @@ enum { static void mwl_printrxbuf(const struct mwl_rxbuf *bf, u_int ix); static void mwl_printtxbuf(const struct mwl_txbuf *bf, u_int qnum, u_int ix); #else -#define IFF_DUMPPKTS_RECV(sc, wh) 0 -#define IFF_DUMPPKTS_XMIT(sc) 0 -#define DPRINTF(sc, m, fmt, ...) do { (void )sc; } while (0) -#define KEYPRINTF(sc, k, mac) do { (void )sc; } while (0) +#define IFF_DUMPPKTS_RECV(sc, wh) \ + ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) +#define IFF_DUMPPKTS_XMIT(sc) \ + ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) +#define DPRINTF(sc, m, fmt, ...) do { \ + (void) sc; \ +} while (0) +#define KEYPRINTF(sc, k, mac) do { \ + (void) sc; \ +} while (0) #endif static MALLOC_DEFINE(M_MWLDEV, "mwldev", "mwl driver dma buffers"); @@ -286,22 +293,34 @@ WR4(struct mwl_softc *sc, bus_size_t off, uint32_t val) int mwl_attach(uint16_t devid, struct mwl_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; struct mwl_hal *mh; int error = 0; DPRINTF(sc, MWL_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "cannot if_alloc()\n"); + return ENOSPC; + } + ic = ifp->if_l2com; + /* * Setup the RX free list lock early, so it can be consistently * removed. */ MWL_RXFREE_INIT(sc); + /* set these up early for if_printf use */ + if_initname(ifp, device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev)); + mh = mwl_hal_attach(sc->sc_dev, devid, sc->sc_io1h, sc->sc_io1t, sc->sc_dmat); if (mh == NULL) { - device_printf(sc->sc_dev, "unable to attach HAL\n"); + if_printf(ifp, "unable to attach HAL\n"); error = EIO; goto bad; } @@ -312,12 +331,12 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) * needed so setting up the wrong mode isn't a big deal. */ if (mwl_hal_fwload(mh, NULL) != 0) { - device_printf(sc->sc_dev, "unable to setup builtin firmware\n"); + if_printf(ifp, "unable to setup builtin firmware\n"); error = EIO; goto bad1; } if (mwl_hal_gethwspecs(mh, &sc->sc_hwspecs) != 0) { - device_printf(sc->sc_dev, "unable to fetch h/w specs\n"); + if_printf(ifp, "unable to fetch h/w specs\n"); error = EIO; goto bad1; } @@ -337,8 +356,7 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) */ error = mwl_dma_setup(sc); if (error != 0) { - device_printf(sc->sc_dev, "failed to setup descriptors: %d\n", - error); + if_printf(ifp, "failed to setup descriptors: %d\n", error); goto bad1; } error = mwl_setupdma(sc); /* push to firmware */ @@ -347,12 +365,11 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) callout_init(&sc->sc_timer, 1); callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); sc->sc_tq = taskqueue_create("mwl_taskq", M_NOWAIT, taskqueue_thread_enqueue, &sc->sc_tq); taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, - "%s taskq", device_get_nameunit(sc->sc_dev)); + "%s taskq", ifp->if_xname); TASK_INIT(&sc->sc_rxtask, 0, mwl_rx_proc, sc); TASK_INIT(&sc->sc_radartask, 0, mwl_radar_proc, sc); @@ -361,9 +378,8 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) /* NB: insure BK queue is the lowest priority h/w queue */ if (!mwl_tx_setup(sc, WME_AC_BK, MWL_WME_AC_BK)) { - device_printf(sc->sc_dev, - "unable to setup xmit queue for %s traffic!\n", - ieee80211_wme_acnames[WME_AC_BK]); + if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", + ieee80211_wme_acnames[WME_AC_BK]); error = EIO; goto bad2; } @@ -387,6 +403,16 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) } TASK_INIT(&sc->sc_txtask, 0, mwl_tx_proc, sc); + ifp->if_softc = sc; + ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_start = mwl_start; + ifp->if_ioctl = mwl_ioctl; + ifp->if_init = mwl_init; + 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(sc->sc_dev); /* XXX not right but it's not used anywhere important */ @@ -454,10 +480,8 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) ic->ic_headroom = sizeof(struct mwltxrec) - sizeof(struct ieee80211_frame); - IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_hwspecs.macAddr); - /* call MI attach routine. */ - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_hwspecs.macAddr); ic->ic_setregdomain = mwl_setregdomain; ic->ic_getradiocaps = mwl_getradiocaps; /* override default methods */ @@ -467,9 +491,6 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) ic->ic_update_mcast = mwl_update_mcast; ic->ic_update_promisc = mwl_update_promisc; ic->ic_wme.wme_update = mwl_wme_update; - ic->ic_transmit = mwl_transmit; - ic->ic_ioctl = mwl_ioctl; - ic->ic_parent = mwl_parent; ic->ic_node_alloc = mwl_node_alloc; sc->sc_node_cleanup = ic->ic_node_cleanup; @@ -516,6 +537,7 @@ bad1: mwl_hal_detach(mh); bad: MWL_RXFREE_DESTROY(sc); + if_free(ifp); sc->sc_invalid = 1; return error; } @@ -523,11 +545,13 @@ bad: int mwl_detach(struct mwl_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - MWL_LOCK(sc); - mwl_stop(sc); - MWL_UNLOCK(sc); + DPRINTF(sc, MWL_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); + + mwl_stop(ifp, 1); /* * NB: the order of these is important: * o call the 802.11 layer before detaching the hal to @@ -546,7 +570,7 @@ mwl_detach(struct mwl_softc *sc) MWL_RXFREE_DESTROY(sc); mwl_tx_cleanup(sc); mwl_hal_detach(sc->sc_mh); - mbufq_drain(&sc->sc_snd); + if_free(ifp); return 0; } @@ -577,7 +601,7 @@ assign_address(struct mwl_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN], int clone) } static void -reclaim_address(struct mwl_softc *sc, const uint8_t mac[IEEE80211_ADDR_LEN]) +reclaim_address(struct mwl_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN]) { int i = mac[0] >> 2; if (i != 0 || --sc->sc_nbssid0 == 0) @@ -590,7 +614,8 @@ mwl_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac0[IEEE80211_ADDR_LEN]) { - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; struct mwl_hal *mh = sc->sc_mh; struct ieee80211vap *vap, *apvap; struct mwl_hal_vap *hvap; @@ -636,7 +661,17 @@ mwl_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, return NULL; } - mvp = malloc(sizeof(struct mwl_vap), M_80211_VAP, M_WAITOK | M_ZERO); + mvp = (struct mwl_vap *) malloc(sizeof(struct mwl_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (mvp == NULL) { + if (hvap != NULL) { + mwl_hal_delvap(hvap); + if ((flags & IEEE80211_CLONE_MACADDR) == 0) + reclaim_address(sc, mac); + } + /* XXX msg */ + return NULL; + } mvp->mv_hvap = hvap; if (opmode == IEEE80211_M_WDS) { /* @@ -651,7 +686,9 @@ mwl_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, KASSERT(mvp->mv_ap_hvap != NULL, ("no ap vap")); } vap = &mvp->mv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); + if (hvap != NULL) + IEEE80211_ADDR_COPY(vap->iv_myaddr, mac); /* override with driver methods */ mvp->mv_newstate = vap->iv_newstate; vap->iv_newstate = mwl_newstate; @@ -676,8 +713,7 @@ mwl_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_4; /* complete setup */ - ieee80211_vap_attach(vap, mwl_media_change, ieee80211_media_status, - mac); + ieee80211_vap_attach(vap, mwl_media_change, ieee80211_media_status); switch (vap->iv_opmode) { case IEEE80211_M_HOSTAP: @@ -716,13 +752,14 @@ static void mwl_vap_delete(struct ieee80211vap *vap) { struct mwl_vap *mvp = MWL_VAP(vap); - struct mwl_softc *sc = vap->iv_ic->ic_softc; + struct ifnet *parent = vap->iv_ic->ic_ifp; + struct mwl_softc *sc = parent->if_softc; struct mwl_hal *mh = sc->sc_mh; struct mwl_hal_vap *hvap = mvp->mv_hvap; enum ieee80211_opmode opmode = vap->iv_opmode; /* XXX disallow ap vap delete if WDS still present */ - if (sc->sc_running) { + if (parent->if_drv_flags & IFF_DRV_RUNNING) { /* quiesce h/w while we remove the vap */ mwl_hal_intrset(mh, 0); /* disable interrupts */ } @@ -749,31 +786,31 @@ mwl_vap_delete(struct ieee80211vap *vap) } mwl_cleartxq(sc, vap); free(mvp, M_80211_VAP); - if (sc->sc_running) + if (parent->if_drv_flags & IFF_DRV_RUNNING) mwl_hal_intrset(mh, sc->sc_imask); } void mwl_suspend(struct mwl_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; - MWL_LOCK(sc); - mwl_stop(sc); - MWL_UNLOCK(sc); + DPRINTF(sc, MWL_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); + + mwl_stop(ifp, 1); } void mwl_resume(struct mwl_softc *sc) { - int error = EDOOFUS; + struct ifnet *ifp = sc->sc_ifp; - MWL_LOCK(sc); - if (sc->sc_ic.ic_nrunning > 0) - error = mwl_init(sc); - MWL_UNLOCK(sc); + DPRINTF(sc, MWL_DEBUG_ANY, "%s: if_flags %x\n", + __func__, ifp->if_flags); - if (error == 0) - ieee80211_start_all(&sc->sc_ic); /* start all vap's */ + if (ifp->if_flags & IFF_UP) + mwl_init(sc); } void @@ -781,9 +818,7 @@ mwl_shutdown(void *arg) { struct mwl_softc *sc = arg; - MWL_LOCK(sc); - mwl_stop(sc); - MWL_UNLOCK(sc); + mwl_stop(sc->sc_ifp, 1); } /* @@ -849,7 +884,8 @@ static void mwl_radar_proc(void *arg, int pending) { struct mwl_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, MWL_DEBUG_ANY, "%s: radar detected, pending %u\n", __func__, pending); @@ -866,7 +902,8 @@ static void mwl_chanswitch_proc(void *arg, int pending) { struct mwl_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, MWL_DEBUG_ANY, "%s: channel switch notice, pending %u\n", __func__, pending); @@ -994,7 +1031,8 @@ mwl_setupdma(struct mwl_softc *sc) static int mwl_setcurchanrates(struct mwl_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct ieee80211_rateset *rs; MWL_HAL_TXRATE rates; @@ -1107,7 +1145,8 @@ mwl_map2regioncode(const struct ieee80211_regdomain *rd) static int mwl_hal_reset(struct mwl_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mwl_hal *mh = sc->sc_mh; mwl_hal_setantenna(mh, WL_ANTENNATYPE_RX, sc->sc_rxantenna); @@ -1129,24 +1168,28 @@ mwl_hal_reset(struct mwl_softc *sc) } static int -mwl_init(struct mwl_softc *sc) +mwl_init_locked(struct mwl_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct mwl_hal *mh = sc->sc_mh; int error = 0; + DPRINTF(sc, MWL_DEBUG_ANY, "%s: if_flags 0x%x\n", + __func__, ifp->if_flags); + MWL_LOCK_ASSERT(sc); /* * Stop anything previously setup. This is safe * whether this is the first time through or not. */ - mwl_stop(sc); + mwl_stop_locked(ifp, 0); /* * Push vap-independent state to the firmware. */ if (!mwl_hal_reset(sc)) { - device_printf(sc->sc_dev, "unable to reset hardware\n"); + if_printf(ifp, "unable to reset hardware\n"); return EIO; } @@ -1155,7 +1198,7 @@ mwl_init(struct mwl_softc *sc) */ error = mwl_startrecv(sc); if (error != 0) { - device_printf(sc->sc_dev, "unable to start recv logic\n"); + if_printf(ifp, "unable to start recv logic\n"); return error; } @@ -1178,7 +1221,7 @@ mwl_init(struct mwl_softc *sc) | MACREQ_A2HRIC_BIT_TX_ACK ; - sc->sc_running = 1; + ifp->if_drv_flags |= IFF_DRV_RUNNING; mwl_hal_intrset(mh, sc->sc_imask); callout_reset(&sc->sc_watchdog, hz, mwl_watchdog, sc); @@ -1186,21 +1229,54 @@ mwl_init(struct mwl_softc *sc) } static void -mwl_stop(struct mwl_softc *sc) +mwl_init(void *arg) { + struct mwl_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + int error = 0; + + DPRINTF(sc, MWL_DEBUG_ANY, "%s: if_flags 0x%x\n", + __func__, ifp->if_flags); + + MWL_LOCK(sc); + error = mwl_init_locked(sc); + MWL_UNLOCK(sc); + + if (error == 0) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void +mwl_stop_locked(struct ifnet *ifp, int disable) +{ + struct mwl_softc *sc = ifp->if_softc; + + DPRINTF(sc, MWL_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", + __func__, sc->sc_invalid, ifp->if_flags); MWL_LOCK_ASSERT(sc); - if (sc->sc_running) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* * Shutdown the hardware and driver. */ - sc->sc_running = 0; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; callout_stop(&sc->sc_watchdog); sc->sc_tx_timer = 0; mwl_draintxq(sc); } } +static void +mwl_stop(struct ifnet *ifp, int disable) +{ + struct mwl_softc *sc = ifp->if_softc; + + MWL_LOCK(sc); + mwl_stop_locked(ifp, disable); + MWL_UNLOCK(sc); +} + static int mwl_reset_vap(struct ieee80211vap *vap, int state) { @@ -1243,7 +1319,8 @@ mwl_reset(struct ieee80211vap *vap, u_long cmd) if (hvap != NULL) { /* WDS, MONITOR, etc. */ struct ieee80211com *ic = vap->iv_ic; - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; struct mwl_hal *mh = sc->sc_mh; /* XXX handle DWDS sta vap change */ @@ -1309,41 +1386,24 @@ mwl_puttxbuf_tail(struct mwl_txq *txq, struct mwl_txbuf *bf) MWL_TXQ_UNLOCK(txq); } -static int -mwl_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct mwl_softc *sc = ic->ic_softc; - int error; - - MWL_LOCK(sc); - if (!sc->sc_running) { - MWL_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - MWL_UNLOCK(sc); - return (error); - } - mwl_start(sc); - MWL_UNLOCK(sc); - return (0); -} - static void -mwl_start(struct mwl_softc *sc) +mwl_start(struct ifnet *ifp) { + struct mwl_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mwl_txbuf *bf; struct mbuf *m; struct mwl_txq *txq = NULL; /* XXX silence gcc */ int nqueued; - MWL_LOCK_ASSERT(sc); - if (!sc->sc_running || sc->sc_invalid) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) return; nqueued = 0; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + bf = NULL; + IFQ_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; /* * Grab the node for the destination. */ @@ -1361,6 +1421,8 @@ mwl_start(struct mwl_softc *sc) ieee80211_free_node(ni); #ifdef MWL_TX_NODROP sc->sc_stats.mst_tx_qstop++; + /* XXX blocks other traffic */ + ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; #else DPRINTF(sc, MWL_DEBUG_XMIT, @@ -1374,8 +1436,7 @@ mwl_start(struct mwl_softc *sc) * Pass the frame to the h/w for transmission. */ if (mwl_tx_start(sc, ni, bf, m)) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); mwl_puttxbuf_head(txq, bf); ieee80211_free_node(ni); continue; @@ -1413,11 +1474,12 @@ mwl_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; struct mwl_txbuf *bf; struct mwl_txq *txq; - if (!sc->sc_running || sc->sc_invalid) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { ieee80211_free_node(ni); m_freem(m); return ENETDOWN; @@ -1434,6 +1496,8 @@ mwl_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, bf = mwl_gettxbuf(sc, txq); if (bf == NULL) { sc->sc_stats.mst_tx_qstop++; + /* XXX blocks other traffic */ + ifp->if_drv_flags |= IFF_DRV_OACTIVE; ieee80211_free_node(ni); m_freem(m); return ENOBUFS; @@ -1442,6 +1506,7 @@ mwl_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, * Pass the frame to the h/w for transmission. */ if (mwl_tx_start(sc, ni, bf, m)) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); mwl_puttxbuf_head(txq, bf); ieee80211_free_node(ni); @@ -1516,7 +1581,7 @@ static int mwl_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) { - struct mwl_softc *sc = vap->iv_ic->ic_softc; + struct mwl_softc *sc = vap->iv_ic->ic_ifp->if_softc; if (k->wk_keyix != IEEE80211_KEYIX_NONE || (k->wk_flags & IEEE80211_KEY_GROUP)) { @@ -1544,7 +1609,7 @@ mwl_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, static int mwl_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) { - struct mwl_softc *sc = vap->iv_ic->ic_softc; + struct mwl_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct mwl_hal_vap *hvap = MWL_VAP(vap)->mv_hvap; MWL_HAL_KEYVAL hk; const uint8_t bcastaddr[IEEE80211_ADDR_LEN] = @@ -1611,7 +1676,7 @@ mwl_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, #define IEEE80211_IS_STATICKEY(k) \ (((k)->wk_flags & (GRPXMIT|IEEE80211_KEY_RECV)) == \ (GRPXMIT|IEEE80211_KEY_RECV)) - struct mwl_softc *sc = vap->iv_ic->ic_softc; + struct mwl_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct mwl_hal_vap *hvap = MWL_VAP(vap)->mv_hvap; const struct ieee80211_cipher *cip = k->wk_cipher; const uint8_t *macaddr; @@ -1726,6 +1791,7 @@ mwl_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, static void mwl_setmcastfilter(struct mwl_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; #if 0 struct ether_multi *enm; struct ether_multistep estep; @@ -1749,13 +1815,17 @@ mwl_setmcastfilter(struct mwl_softc *sc) } ifp->if_flags &= ~IFF_ALLMULTI; mwl_hal_setmcast(sc->sc_mh, nmc, macs); +#else + /* XXX no mcast filter support; we get everything */ + ifp->if_flags |= IFF_ALLMULTI; #endif } static int mwl_mode_init(struct mwl_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mwl_hal *mh = sc->sc_mh; /* @@ -1764,7 +1834,7 @@ mwl_mode_init(struct mwl_softc *sc) * identify internal requests (from the bridge) * versus external requests such as for tcpdump. */ - mwl_hal_setpromisc(mh, ic->ic_promisc > 0 && + mwl_hal_setpromisc(mh, (ifp->if_flags & IFF_PROMISC) && ic->ic_opmode != IEEE80211_M_HOSTAP); mwl_setmcastfilter(sc); @@ -1794,7 +1864,8 @@ mwl_update_promisc(struct ieee80211com *ic) { struct mwl_softc *sc = ic->ic_softc; - mwl_hal_setpromisc(sc->sc_mh, ic->ic_promisc > 0); + mwl_hal_setpromisc(sc->sc_mh, + (ic->ic_ifp->if_flags & IFF_PROMISC) != 0); } /* @@ -1811,7 +1882,7 @@ mwl_updateslot(struct ieee80211com *ic) int prot; /* NB: can be called early; suppress needless cmds */ - if (!sc->sc_running) + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; /* @@ -1933,6 +2004,7 @@ mwl_desc_setup(struct mwl_softc *sc, const char *name, struct mwl_descdma *dd, int nbuf, size_t bufsize, int ndesc, size_t descsize) { + struct ifnet *ifp = sc->sc_ifp; uint8_t *ds; int error; @@ -1960,7 +2032,7 @@ mwl_desc_setup(struct mwl_softc *sc, const char *name, NULL, /* lockarg */ &dd->dd_dmat); if (error != 0) { - device_printf(sc->sc_dev, "cannot allocate %s DMA tag\n", dd->dd_name); + if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name); return error; } @@ -1969,7 +2041,7 @@ mwl_desc_setup(struct mwl_softc *sc, const char *name, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dd->dd_dmamap); if (error != 0) { - device_printf(sc->sc_dev, "unable to alloc memory for %u %s descriptors, " + if_printf(ifp, "unable to alloc memory for %u %s descriptors, " "error %u\n", nbuf * ndesc, dd->dd_name, error); goto fail1; } @@ -1979,7 +2051,7 @@ mwl_desc_setup(struct mwl_softc *sc, const char *name, mwl_load_cb, &dd->dd_desc_paddr, BUS_DMA_NOWAIT); if (error != 0) { - device_printf(sc->sc_dev, "unable to map %s descriptors, error %u\n", + if_printf(ifp, "unable to map %s descriptors, error %u\n", dd->dd_name, error); goto fail2; } @@ -2037,6 +2109,7 @@ mwl_txq_reset(struct mwl_softc *sc, struct mwl_txq *txq) static int mwl_txdma_setup(struct mwl_softc *sc, struct mwl_txq *txq) { + struct ifnet *ifp = sc->sc_ifp; int error, bsize, i; struct mwl_txbuf *bf; struct mwl_txdesc *ds; @@ -2051,7 +2124,7 @@ mwl_txdma_setup(struct mwl_softc *sc, struct mwl_txq *txq) bsize = mwl_txbuf * sizeof(struct mwl_txbuf); bf = malloc(bsize, M_MWLDEV, M_NOWAIT | M_ZERO); if (bf == NULL) { - device_printf(sc->sc_dev, "malloc of %u tx buffers failed\n", + if_printf(ifp, "malloc of %u tx buffers failed\n", mwl_txbuf); return ENOMEM; } @@ -2064,7 +2137,7 @@ mwl_txdma_setup(struct mwl_softc *sc, struct mwl_txq *txq) error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap); if (error != 0) { - device_printf(sc->sc_dev, "unable to create dmamap for tx " + if_printf(ifp, "unable to create dmamap for tx " "buffer %u, error %u\n", i, error); return error; } @@ -2099,6 +2172,7 @@ mwl_txdma_cleanup(struct mwl_softc *sc, struct mwl_txq *txq) static int mwl_rxdma_setup(struct mwl_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int error, jumbosize, bsize, i; struct mwl_rxbuf *bf; struct mwl_jumbo *rbuf; @@ -2122,7 +2196,7 @@ mwl_rxdma_setup(struct mwl_softc *sc) * us while frames are processed. */ if (mwl_rxbuf < 2*mwl_rxdesc) { - device_printf(sc->sc_dev, + if_printf(ifp, "too few rx dma buffers (%d); increasing to %d\n", mwl_rxbuf, 2*mwl_rxdesc); mwl_rxbuf = 2*mwl_rxdesc; @@ -2143,7 +2217,7 @@ mwl_rxdma_setup(struct mwl_softc *sc) NULL, /* lockarg */ &sc->sc_rxdmat); if (error != 0) { - device_printf(sc->sc_dev, "could not create rx DMA tag\n"); + if_printf(ifp, "could not create rx DMA tag\n"); return error; } @@ -2151,7 +2225,7 @@ mwl_rxdma_setup(struct mwl_softc *sc) BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->sc_rxmap); if (error != 0) { - device_printf(sc->sc_dev, "could not alloc %ju bytes of rx DMA memory\n", + if_printf(ifp, "could not alloc %ju bytes of rx DMA memory\n", (uintmax_t) sc->sc_rxmemsize); return error; } @@ -2161,7 +2235,7 @@ mwl_rxdma_setup(struct mwl_softc *sc) mwl_load_cb, &sc->sc_rxmem_paddr, BUS_DMA_NOWAIT); if (error != 0) { - device_printf(sc->sc_dev, "could not load rx DMA map\n"); + if_printf(ifp, "could not load rx DMA map\n"); return error; } @@ -2171,7 +2245,7 @@ mwl_rxdma_setup(struct mwl_softc *sc) bsize = mwl_rxdesc * sizeof(struct mwl_rxbuf); bf = malloc(bsize, M_MWLDEV, M_NOWAIT | M_ZERO); if (bf == NULL) { - device_printf(sc->sc_dev, "malloc of %u rx buffers failed\n", bsize); + if_printf(ifp, "malloc of %u rx buffers failed\n", bsize); return error; } sc->sc_rxdma.dd_bufptr = bf; @@ -2255,7 +2329,7 @@ static struct ieee80211_node * mwl_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic = vap->iv_ic; - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; const size_t space = sizeof(struct mwl_node); struct mwl_node *mn; @@ -2272,7 +2346,7 @@ static void mwl_node_cleanup(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; struct mwl_node *mn = MWL_NODE(ni); DPRINTF(sc, MWL_DEBUG_NODE, "%s: ni %p ic %p staid %d\n", @@ -2367,7 +2441,7 @@ static void mwl_node_drain(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; struct mwl_node *mn = MWL_NODE(ni); DPRINTF(sc, MWL_DEBUG_NODE, "%s: ni %p vap %p staid %d\n", @@ -2622,7 +2696,8 @@ mwl_rx_proc(void *arg, int npending) #define IEEE80211_DIR_DSTODS(wh) \ ((((const struct ieee80211_frame *)wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) struct mwl_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mwl_rxbuf *bf; struct mwl_rxdesc *ds; struct mbuf *m; @@ -2669,7 +2744,7 @@ mwl_rx_proc(void *arg, int npending) #endif status = ds->Status; if (status & EAGLE_RXD_STATUS_DECRYPT_ERR_MASK) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); sc->sc_stats.mst_rx_crypto++; /* * NB: Check EAGLE_RXD_STATUS_GENERAL_DECRYPT_ERR @@ -2765,6 +2840,7 @@ mwl_rx_proc(void *arg, int npending) data, sc, 0, EXT_NET_DRV); m->m_data += off - hdrlen; m->m_pkthdr.len = m->m_len = pktlen; + m->m_pkthdr.rcvif = ifp; /* NB: dma buffer assumed read-only */ /* @@ -2814,6 +2890,8 @@ mwl_rx_proc(void *arg, int npending) ieee80211_dump_pkt(ic, mtod(m, caddr_t), len, ds->Rate, rssi); } + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + /* dispatch */ ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh); @@ -2840,10 +2918,11 @@ rx_next: rx_stop: sc->sc_rxnext = bf; - if (mbufq_first(&sc->sc_snd) != NULL) { + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) { /* NB: kick fw; the tx thread may have been preempted */ mwl_hal_txstart(sc->sc_mh, 0); - mwl_start(sc); + mwl_start(ifp); } #undef IEEE80211_DIR_DSTODS } @@ -2908,7 +2987,8 @@ static int mwl_txq_update(struct mwl_softc *sc, int ac) { #define MWL_EXPONENT_TO_VALUE(v) ((1<<v)-1) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mwl_txq *txq = sc->sc_ac2q[ac]; struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; struct mwl_hal *mh = sc->sc_mh; @@ -2936,7 +3016,7 @@ mwl_txq_update(struct mwl_softc *sc, int ac) static int mwl_wme_update(struct ieee80211com *ic) { - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; return !mwl_txq_update(sc, WME_AC_BE) || !mwl_txq_update(sc, WME_AC_BK) || @@ -3093,7 +3173,8 @@ mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf * { #define IEEE80211_DIR_DSTODS(wh) \ ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; int error, iswep, ismcast; int hdrlen, copyhdrlen, pktlen; @@ -3310,7 +3391,7 @@ mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf * ds->TxPriority = txq->qnum; break; default: - device_printf(sc->sc_dev, "bogus frame type 0x%x (%s)\n", + if_printf(ifp, "bogus frame type 0x%x (%s)\n", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); sc->sc_stats.mst_tx_badframetype++; m_freem(m0); @@ -3327,6 +3408,7 @@ mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf * STAILQ_INSERT_TAIL(&txq->active, bf, bf_list); MWL_TXDESC_SYNC(txq, ds, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); sc->sc_tx_timer = 5; MWL_TXQ_UNLOCK(txq); @@ -3352,7 +3434,8 @@ mwl_tx_processq(struct mwl_softc *sc, struct mwl_txq *txq) { #define EAGLE_TXD_STATUS_MCAST \ (EAGLE_TXD_STATUS_MULTICAST_TX | EAGLE_TXD_STATUS_BROADCAST_TX) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mwl_txbuf *bf; struct mwl_txdesc *ds; struct ieee80211_node *ni; @@ -3414,18 +3497,32 @@ mwl_tx_processq(struct mwl_softc *sc, struct mwl_txq *txq) if (bf->bf_m->m_flags & M_FF) sc->sc_stats.mst_ff_txerr++; } - if (bf->bf_m->m_flags & M_TXCB) + /* + * Do any tx complete callback. Note this must + * be done before releasing the node reference. + * XXX no way to figure out if frame was ACK'd + */ + if (bf->bf_m->m_flags & M_TXCB) { /* XXX strip fw len in case header inspected */ m_adj(bf->bf_m, sizeof(uint16_t)); - ieee80211_tx_complete(ni, bf->bf_m, - (status & EAGLE_TXD_STATUS_OK) == 0); - } else - m_freem(bf->bf_m); + ieee80211_process_callback(ni, bf->bf_m, + (status & EAGLE_TXD_STATUS_OK) == 0); + } + /* + * Reclaim reference to node. + * + * NB: the node may be reclaimed here if, for example + * this is a DEAUTH message that was sent and the + * node was timed out due to inactivity. + */ + ieee80211_free_node(ni); + } ds->Status = htole32(EAGLE_TXD_STATUS_IDLE); bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); + m_freem(bf->bf_m); mwl_puttxbuf_tail(txq, bf); } @@ -3441,6 +3538,7 @@ static void mwl_tx_proc(void *arg, int npending) { struct mwl_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; int nreaped; /* @@ -3457,11 +3555,12 @@ mwl_tx_proc(void *arg, int npending) nreaped += mwl_tx_processq(sc, &sc->sc_txq[3]); if (nreaped != 0) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_tx_timer = 0; - if (mbufq_first(&sc->sc_snd) != NULL) { + if (!IFQ_IS_EMPTY(&ifp->if_snd)) { /* NB: kick fw; the tx thread may have been preempted */ mwl_hal_txstart(sc->sc_mh, 0); - mwl_start(sc); + mwl_start(ifp); } } } @@ -3488,7 +3587,8 @@ mwl_tx_draintxq(struct mwl_softc *sc, struct mwl_txq *txq) MWL_TXQ_UNLOCK(txq); #ifdef MWL_DEBUG if (sc->sc_debug & MWL_DEBUG_RESET) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct mwltxrec *tr = mtod(bf->bf_m, const struct mwltxrec *); mwl_printtxbuf(bf, txq->qnum, ix); @@ -3516,10 +3616,12 @@ mwl_tx_draintxq(struct mwl_softc *sc, struct mwl_txq *txq) static void mwl_draintxq(struct mwl_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int i; for (i = 0; i < MWL_NUM_TX_QUEUES; i++) mwl_tx_draintxq(sc, &sc->sc_txq[i]); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_tx_timer = 0; } @@ -3569,7 +3671,7 @@ static int mwl_recv_action(struct ieee80211_node *ni, const struct ieee80211_frame *wh, const uint8_t *frm, const uint8_t *efrm) { - struct mwl_softc *sc = ni->ni_ic->ic_softc; + struct mwl_softc *sc = ni->ni_ic->ic_ifp->if_softc; const struct ieee80211_action *ia; ia = (const struct ieee80211_action *) frm; @@ -3590,7 +3692,7 @@ static int mwl_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int dialogtoken, int baparamset, int batimeout) { - struct mwl_softc *sc = ni->ni_ic->ic_softc; + struct mwl_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct ieee80211vap *vap = ni->ni_vap; struct mwl_node *mn = MWL_NODE(ni); struct mwl_bastate *bas; @@ -3662,7 +3764,7 @@ static int mwl_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int code, int baparamset, int batimeout) { - struct mwl_softc *sc = ni->ni_ic->ic_softc; + struct mwl_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct mwl_bastate *bas; bas = tap->txa_private; @@ -3728,7 +3830,7 @@ mwl_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, static void mwl_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { - struct mwl_softc *sc = ni->ni_ic->ic_softc; + struct mwl_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct mwl_bastate *bas; bas = tap->txa_private; @@ -3821,7 +3923,8 @@ static int mwl_chan_set(struct mwl_softc *sc, struct ieee80211_channel *chan) { struct mwl_hal *mh = sc->sc_mh; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; MWL_HAL_CHANNEL hchan; int maxtxpow; @@ -3877,7 +3980,8 @@ mwl_chan_set(struct mwl_softc *sc, struct ieee80211_channel *chan) static void mwl_scan_start(struct ieee80211com *ic) { - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; DPRINTF(sc, MWL_DEBUG_STATE, "%s\n", __func__); } @@ -3885,7 +3989,8 @@ mwl_scan_start(struct ieee80211com *ic) static void mwl_scan_end(struct ieee80211com *ic) { - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; DPRINTF(sc, MWL_DEBUG_STATE, "%s\n", __func__); } @@ -3893,7 +3998,8 @@ mwl_scan_end(struct ieee80211com *ic) static void mwl_set_channel(struct ieee80211com *ic) { - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; (void) mwl_chan_set(sc, ic->ic_curchan); } @@ -3908,7 +4014,7 @@ static void mwl_startcsa(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; MWL_HAL_CHANNEL hchan; if (sc->sc_csapending) @@ -4109,7 +4215,8 @@ mwl_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct mwl_hal_vap *hvap = mvp->mv_hvap; struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni = NULL; - struct mwl_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct mwl_softc *sc = ifp->if_softc; struct mwl_hal *mh = sc->sc_mh; enum ieee80211_state ostate = vap->iv_state; int error; @@ -4291,7 +4398,7 @@ static void mwl_newassoc(struct ieee80211_node *ni, int isnew) { struct ieee80211vap *vap = ni->ni_vap; - struct mwl_softc *sc = vap->iv_ic->ic_softc; + struct mwl_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct mwl_node *mn = MWL_NODE(ni); MWL_HAL_PEERINFO pi; uint16_t aid; @@ -4347,7 +4454,7 @@ static int mwl_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, int nchan, struct ieee80211_channel chans[]) { - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; struct mwl_hal *mh = sc->sc_mh; const MWL_HAL_CHANNELINFO *ci; int i; @@ -4365,7 +4472,7 @@ mwl_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, IEEE80211_IS_CHAN_HT40(c) ? MWL_CH_40_MHz_WIDTH : MWL_CH_20_MHz_WIDTH, &ci); } else { - device_printf(sc->sc_dev, + if_printf(ic->ic_ifp, "%s: channel %u freq %u/0x%x not 2.4/5GHz\n", __func__, c->ic_ieee, c->ic_freq, c->ic_flags); return EINVAL; @@ -4391,7 +4498,7 @@ mwl_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, goto next; } } - device_printf(sc->sc_dev, + if_printf(ic->ic_ifp, "%s: no cal data for channel %u ext %u freq %u/0x%x\n", __func__, c->ic_ieee, c->ic_extieee, c->ic_freq, c->ic_flags); @@ -4547,7 +4654,7 @@ static void mwl_getradiocaps(struct ieee80211com *ic, int maxchans, int *nchans, struct ieee80211_channel chans[]) { - struct mwl_softc *sc = ic->ic_softc; + struct mwl_softc *sc = ic->ic_ifp->if_softc; getchannels(sc, maxchans, nchans, chans); } @@ -4555,7 +4662,8 @@ mwl_getradiocaps(struct ieee80211com *ic, static int mwl_getchannels(struct mwl_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; /* * Use the channel info from the hal to craft the @@ -4660,24 +4768,25 @@ mwl_txq_dump(struct mwl_txq *txq) static void mwl_watchdog(void *arg) { - struct mwl_softc *sc = arg; + struct mwl_softc *sc; + struct ifnet *ifp; + sc = arg; callout_reset(&sc->sc_watchdog, hz, mwl_watchdog, sc); if (sc->sc_tx_timer == 0 || --sc->sc_tx_timer > 0) return; - if (sc->sc_running && !sc->sc_invalid) { + ifp = sc->sc_ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && !sc->sc_invalid) { if (mwl_hal_setkeepalive(sc->sc_mh)) - device_printf(sc->sc_dev, - "transmit timeout (firmware hung?)\n"); + if_printf(ifp, "transmit timeout (firmware hung?)\n"); else - device_printf(sc->sc_dev, - "transmit timeout\n"); + if_printf(ifp, "transmit timeout\n"); #if 0 - mwl_reset(sc); + mwl_reset(ifp); mwl_txq_dump(&sc->sc_txq[0]);/*XXX*/ #endif - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); sc->sc_stats.mst_watchdog++; } } @@ -4776,22 +4885,28 @@ mwl_ioctl_reset(struct mwl_softc *sc, struct mwl_diag *md) } #endif /* MWL_DIAGAPI */ -static void -mwl_parent(struct ieee80211com *ic) +static int +mwl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct mwl_softc *sc = ic->ic_softc; - int startall = 0; +#define IS_RUNNING(ifp) \ + ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + struct mwl_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0, startall; - MWL_LOCK(sc); - if (ic->ic_nrunning > 0) { - if (sc->sc_running) { + switch (cmd) { + case SIOCSIFFLAGS: + MWL_LOCK(sc); + startall = 0; + if (IS_RUNNING(ifp)) { /* * To avoid rescanning another access point, * do not call mwl_init() here. Instead, * only reflect promisc mode settings. */ mwl_mode_init(sc); - } else { + } else if (ifp->if_flags & IFF_UP) { /* * Beware of being called during attach/detach * to reset promiscuous mode. In that case we @@ -4802,42 +4917,30 @@ mwl_parent(struct ieee80211com *ic) * probably a better way to deal with this. */ if (!sc->sc_invalid) { - mwl_init(sc); /* XXX lose error */ + mwl_init_locked(sc); /* XXX lose error */ startall = 1; } - } - } else - mwl_stop(sc); - MWL_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); -} - -static int -mwl_ioctl(struct ieee80211com *ic, u_long cmd, void *data) -{ - struct mwl_softc *sc = ic->ic_softc; - struct ifreq *ifr = data; - int error = 0; - - switch (cmd) { + } else + mwl_stop_locked(ifp, 1); + MWL_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); + break; case SIOCGMVSTATS: mwl_hal_gethwstats(sc->sc_mh, &sc->sc_stats.hw_stats); -#if 0 /* NB: embed these numbers to get a consistent view */ sc->sc_stats.mst_tx_packets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS); sc->sc_stats.mst_rx_packets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS); -#endif /* * NB: Drop the softc lock in case of a page fault; * we'll accept any potential inconsisentcy in the * statistics. The alternative is to copy the data * to a local structure. */ - return (copyout(&sc->sc_stats, - ifr->ifr_data, sizeof (sc->sc_stats))); + return copyout(&sc->sc_stats, + ifr->ifr_data, sizeof (sc->sc_stats)); #ifdef MWL_DIAGAPI case SIOCGMVDIAG: /* XXX check privs */ @@ -4849,11 +4952,18 @@ mwl_ioctl(struct ieee80211com *ic, u_long cmd, void *data) MWL_UNLOCK(sc); break; #endif /* MWL_DIAGAPI */ + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; default: - error = ENOTTY; + error = EINVAL; break; } - return (error); + return error; +#undef IS_RUNNING } #ifdef MWL_DEBUG @@ -4893,8 +5003,9 @@ mwl_sysctlattach(struct mwl_softc *sc) static void mwl_announce(struct mwl_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; - device_printf(sc->sc_dev, "Rev A%d hardware, v%d.%d.%d.%d firmware (regioncode %d)\n", + if_printf(ifp, "Rev A%d hardware, v%d.%d.%d.%d firmware (regioncode %d)\n", sc->sc_hwspecs.hwVersion, (sc->sc_hwspecs.fwReleaseNumber>>24) & 0xff, (sc->sc_hwspecs.fwReleaseNumber>>16) & 0xff, @@ -4907,20 +5018,20 @@ mwl_announce(struct mwl_softc *sc) int i; for (i = 0; i <= WME_AC_VO; i++) { struct mwl_txq *txq = sc->sc_ac2q[i]; - device_printf(sc->sc_dev, "Use hw queue %u for %s traffic\n", + if_printf(ifp, "Use hw queue %u for %s traffic\n", txq->qnum, ieee80211_wme_acnames[i]); } } if (bootverbose || mwl_rxdesc != MWL_RXDESC) - device_printf(sc->sc_dev, "using %u rx descriptors\n", mwl_rxdesc); + if_printf(ifp, "using %u rx descriptors\n", mwl_rxdesc); if (bootverbose || mwl_rxbuf != MWL_RXBUF) - device_printf(sc->sc_dev, "using %u rx buffers\n", mwl_rxbuf); + if_printf(ifp, "using %u rx buffers\n", mwl_rxbuf); if (bootverbose || mwl_txbuf != MWL_TXBUF) - device_printf(sc->sc_dev, "using %u tx buffers\n", mwl_txbuf); + if_printf(ifp, "using %u tx buffers\n", mwl_txbuf); if (bootverbose && mwl_hal_ismbsscapable(sc->sc_mh)) - device_printf(sc->sc_dev, "multi-bss support\n"); + if_printf(ifp, "multi-bss support\n"); #ifdef MWL_TX_NODROP if (bootverbose) - device_printf(sc->sc_dev, "no tx drop\n"); + if_printf(ifp, "no tx drop\n"); #endif } diff --git a/sys/dev/mwl/if_mwl_pci.c b/sys/dev/mwl/if_mwl_pci.c index d9da128..ef7009c 100644 --- a/sys/dev/mwl/if_mwl_pci.c +++ b/sys/dev/mwl/if_mwl_pci.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> -#include <sys/mbuf.h> #include <sys/mutex.h> #include <sys/errno.h> diff --git a/sys/dev/mwl/if_mwlvar.h b/sys/dev/mwl/if_mwlvar.h index 4a4b338..7071ba0 100644 --- a/sys/dev/mwl/if_mwlvar.h +++ b/sys/dev/mwl/if_mwlvar.h @@ -244,8 +244,7 @@ struct mwl_vap { #define MWL_VAP_CONST(vap) ((const struct mwl_vap *)(vap)) struct mwl_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; /* interface common */ struct mwl_stats sc_stats; /* interface statistics */ int sc_debug; device_t sc_dev; @@ -258,8 +257,7 @@ struct mwl_softc { struct taskqueue *sc_tq; /* private task queue */ struct callout sc_watchdog; int sc_tx_timer; - unsigned int sc_running : 1, - sc_invalid : 1, /* disable hardware accesses */ + unsigned int sc_invalid : 1, /* disable hardware accesses */ sc_recvsetup:1, /* recv setup */ sc_csapending:1,/* 11h channel switch pending */ sc_radarena : 1,/* radar detection enabled */ diff --git a/sys/dev/ral/if_ral_pci.c b/sys/dev/ral/if_ral_pci.c index 42ec034..519b4ca 100644 --- a/sys/dev/ral/if_ral_pci.c +++ b/sys/dev/ral/if_ral_pci.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> -#include <sys/mbuf.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/rman.h> diff --git a/sys/dev/ral/rt2560.c b/sys/dev/ral/rt2560.c index ea9c416..29ce8cb 100644 --- a/sys/dev/ral/rt2560.c +++ b/sys/dev/ral/rt2560.c @@ -127,10 +127,10 @@ static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, struct ieee80211_node *); static int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, struct ieee80211_node *); -static int rt2560_transmit(struct ieee80211com *, struct mbuf *); -static void rt2560_start(struct rt2560_softc *); +static void rt2560_start_locked(struct ifnet *); +static void rt2560_start(struct ifnet *); static void rt2560_watchdog(void *); -static void rt2560_parent(struct ieee80211com *); +static int rt2560_ioctl(struct ifnet *, u_long, caddr_t); static void rt2560_bbp_write(struct rt2560_softc *, uint8_t, uint8_t); static uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); @@ -149,8 +149,7 @@ static void rt2560_set_basicrates(struct rt2560_softc *, const struct ieee80211_rateset *); static void rt2560_update_led(struct rt2560_softc *, int, int); static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); -static void rt2560_set_macaddr(struct rt2560_softc *, - const uint8_t *); +static void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); static void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); static void rt2560_update_promisc(struct ieee80211com *); static const char *rt2560_get_rf(int); @@ -198,9 +197,11 @@ int rt2560_attach(device_t dev, int id) { struct rt2560_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; - uint8_t bands; + struct ieee80211com *ic; + struct ifnet *ifp; int error; + uint8_t bands; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; @@ -208,7 +209,6 @@ rt2560_attach(device_t dev, int id) MTX_DEF | MTX_RECURSE); callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* retrieve RT2560 rev. no */ sc->asic_rev = RAL_READ(sc, RT2560_CSR0); @@ -252,9 +252,27 @@ rt2560_attach(device_t dev, int id) goto fail5; } - /* retrieve MAC address */ - rt2560_get_macaddr(sc, ic->ic_macaddr); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + goto fail6; + } + ic = ifp->if_l2com; + /* retrieve MAC address */ + rt2560_get_macaddr(sc, macaddr); + + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rt2560_init; + ifp->if_ioctl = rt2560_ioctl; + ifp->if_start = rt2560_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(dev); ic->ic_opmode = IEEE80211_M_STA; @@ -285,7 +303,7 @@ rt2560_attach(device_t dev, int id) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_raw_xmit = rt2560_raw_xmit; ic->ic_updateslot = rt2560_update_slot; ic->ic_update_promisc = rt2560_update_promisc; @@ -295,8 +313,6 @@ rt2560_attach(device_t dev, int id) ic->ic_vap_create = rt2560_vap_create; ic->ic_vap_delete = rt2560_vap_delete; - ic->ic_parent = rt2560_parent; - ic->ic_transmit = rt2560_transmit; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -325,6 +341,7 @@ rt2560_attach(device_t dev, int id) return 0; +fail6: rt2560_free_rx_ring(sc, &sc->rxq); fail5: rt2560_free_tx_ring(sc, &sc->bcnq); fail4: rt2560_free_tx_ring(sc, &sc->prioq); fail3: rt2560_free_tx_ring(sc, &sc->atimq); @@ -338,12 +355,12 @@ int rt2560_detach(void *xsc) { struct rt2560_softc *sc = xsc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; rt2560_stop(sc); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); rt2560_free_tx_ring(sc, &sc->txq); rt2560_free_tx_ring(sc, &sc->atimq); @@ -351,6 +368,8 @@ rt2560_detach(void *xsc) rt2560_free_tx_ring(sc, &sc->bcnq); rt2560_free_rx_ring(sc, &sc->rxq); + if_free(ifp); + mtx_destroy(&sc->sc_mtx); return 0; @@ -362,7 +381,7 @@ rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct rt2560_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; struct rt2560_vap *rvp; struct ieee80211vap *vap; @@ -375,7 +394,7 @@ rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_MBSS: /* XXXRP: TBD */ if (!TAILQ_EMPTY(&ic->ic_vaps)) { - device_printf(sc->sc_dev, "only 1 vap supported\n"); + if_printf(ifp, "only 1 vap supported\n"); return NULL; } if (opmode == IEEE80211_M_STA) @@ -384,8 +403,7 @@ rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_WDS: if (TAILQ_EMPTY(&ic->ic_vaps) || ic->ic_opmode != IEEE80211_M_HOSTAP) { - device_printf(sc->sc_dev, - "wds only supported in ap mode\n"); + if_printf(ifp, "wds only supported in ap mode\n"); return NULL; } /* @@ -396,12 +414,15 @@ rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, flags &= ~IEEE80211_CLONE_BSSID; break; default: - device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); + if_printf(ifp, "unknown opmode %d\n", opmode); return NULL; } - rvp = malloc(sizeof(struct rt2560_vap), M_80211_VAP, M_WAITOK | M_ZERO); + rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return NULL; vap = &rvp->ral_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override state transition machine */ rvp->ral_newstate = vap->iv_newstate; @@ -410,8 +431,7 @@ rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); if (TAILQ_FIRST(&ic->ic_vaps) == vap) ic->ic_opmode = opmode; return vap; @@ -431,8 +451,9 @@ void rt2560_resume(void *xsc) { struct rt2560_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; - if (sc->sc_ic.ic_nrunning > 0) + if (ifp->if_flags & IFF_UP) rt2560_init(sc); } @@ -742,7 +763,8 @@ static int rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct rt2560_vap *rvp = RT2560_VAP(vap); - struct rt2560_softc *sc = vap->iv_ic->ic_softc; + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct rt2560_softc *sc = ifp->if_softc; int error; if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { @@ -770,8 +792,7 @@ rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) vap->iv_opmode == IEEE80211_M_MBSS) { m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); if (m == NULL) { - device_printf(sc->sc_dev, - "could not allocate beacon\n"); + if_printf(ifp, "could not allocate beacon\n"); return ENOBUFS; } ieee80211_ref_node(ni); @@ -905,13 +926,14 @@ rt2560_encryption_intr(struct rt2560_softc *sc) static void rt2560_tx_intr(struct rt2560_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; struct mbuf *m; + uint32_t flags; + int retrycnt; struct ieee80211vap *vap; struct ieee80211_node *ni; - uint32_t flags; - int retrycnt, status; bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, BUS_DMASYNC_POSTREAD); @@ -939,7 +961,7 @@ rt2560_tx_intr(struct rt2560_softc *sc) ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &retrycnt, NULL); - status = 0; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); break; case RT2560_TX_SUCCESS_RETRY: @@ -951,7 +973,7 @@ rt2560_tx_intr(struct rt2560_softc *sc) ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &retrycnt, NULL); - status = 0; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); break; case RT2560_TX_FAIL_RETRY: @@ -963,7 +985,7 @@ rt2560_tx_intr(struct rt2560_softc *sc) ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &retrycnt, NULL); - status = 1; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; case RT2560_TX_FAIL_INVALID: @@ -971,16 +993,16 @@ rt2560_tx_intr(struct rt2560_softc *sc) default: device_printf(sc->sc_dev, "sending data frame failed " "0x%08x\n", flags); - status = 1; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->txq.data_dmat, data->map); - - ieee80211_tx_complete(ni, m, status); - data->ni = NULL; + m_freem(m); data->m = NULL; + ieee80211_free_node(data->ni); + data->ni = NULL; /* descriptor is no longer valid */ desc->flags &= ~htole32(RT2560_TX_VALID); @@ -997,13 +1019,19 @@ rt2560_tx_intr(struct rt2560_softc *sc) if (sc->prioq.queued == 0 && sc->txq.queued == 0) sc->sc_tx_timer = 0; - if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) - rt2560_start(sc); + if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { + sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; + if ((sc->sc_flags & + (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + rt2560_start_locked(ifp); + } } static void rt2560_prio_intr(struct rt2560_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; struct ieee80211_node *ni; @@ -1075,8 +1103,13 @@ rt2560_prio_intr(struct rt2560_softc *sc) if (sc->prioq.queued == 0 && sc->txq.queued == 0) sc->sc_tx_timer = 0; - if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) - rt2560_start(sc); + if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { + sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; + if ((sc->sc_flags & + (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + rt2560_start_locked(ifp); + } } /* @@ -1086,7 +1119,8 @@ rt2560_prio_intr(struct rt2560_softc *sc) static void rt2560_decryption_intr(struct rt2560_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rt2560_rx_desc *desc; struct rt2560_rx_data *data; bus_addr_t physaddr; @@ -1112,13 +1146,13 @@ rt2560_decryption_intr(struct rt2560_softc *sc) break; if (data->drop) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1131,7 +1165,7 @@ rt2560_decryption_intr(struct rt2560_softc *sc) */ mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (mnew == NULL) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1154,7 +1188,7 @@ rt2560_decryption_intr(struct rt2560_softc *sc) panic("%s: could not load old rx mbuf", device_get_name(sc->sc_dev)); } - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1167,6 +1201,7 @@ rt2560_decryption_intr(struct rt2560_softc *sc) desc->physaddr = htole32(physaddr); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff; @@ -1286,7 +1321,8 @@ rt2560_beacon_update(struct ieee80211vap *vap, int item) static void rt2560_beacon_expire(struct rt2560_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 rt2560_vap *rvp = RT2560_VAP(vap); struct rt2560_tx_data *data; @@ -1327,6 +1363,7 @@ void rt2560_intr(void *arg) { struct rt2560_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t r; RAL_LOCK(sc); @@ -1335,7 +1372,7 @@ rt2560_intr(void *arg) RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); /* don't re-enable interrupts if we're shutting down */ - if (!(sc->sc_flags & RT2560_F_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RAL_UNLOCK(sc); return; } @@ -1403,7 +1440,8 @@ static void rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t plcp_length; int remainder; @@ -1878,57 +1916,55 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, return 0; } -static int -rt2560_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct rt2560_softc *sc = ic->ic_softc; - int error; - - RAL_LOCK(sc); - if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { - RAL_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RAL_UNLOCK(sc); - return (error); - } - rt2560_start(sc); - RAL_UNLOCK(sc); - - return (0); -} - static void -rt2560_start(struct rt2560_softc *sc) +rt2560_start_locked(struct ifnet *ifp) { - struct ieee80211_node *ni; + struct rt2560_softc *sc = ifp->if_softc; struct mbuf *m; + struct ieee80211_node *ni; RAL_LOCK_ASSERT(sc); - while (sc->txq.queued < RT2560_TX_RING_COUNT - 1 && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + sc->sc_flags |= RT2560_F_DATA_OACTIVE; + break; + } ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; if (rt2560_tx_data(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } + sc->sc_tx_timer = 5; } } static void +rt2560_start(struct ifnet *ifp) +{ + struct rt2560_softc *sc = ifp->if_softc; + + RAL_LOCK(sc); + rt2560_start_locked(ifp); + RAL_UNLOCK(sc); +} + +static void rt2560_watchdog(void *arg) { struct rt2560_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; RAL_LOCK_ASSERT(sc); - KASSERT(sc->sc_flags & RT2560_F_RUNNING, ("not running")); + KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); if (sc->sc_invalid) /* card ejected */ return; @@ -1937,33 +1973,51 @@ rt2560_watchdog(void *arg) rt2560_tx_intr(sc); if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); + if_printf(ifp, "device timeout\n"); rt2560_init_locked(sc); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* NB: callout is reset in rt2560_init() */ return; } callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); } -static void -rt2560_parent(struct ieee80211com *ic) +static int +rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct rt2560_softc *sc = ic->ic_softc; - int startall = 0; + struct rt2560_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; - RAL_LOCK(sc); - if (ic->ic_nrunning > 0) { - if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { - rt2560_init_locked(sc); - startall = 1; - } else - rt2560_update_promisc(ic); - } else if (sc->sc_flags & RT2560_F_RUNNING) - rt2560_stop_locked(sc); - RAL_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + switch (cmd) { + case SIOCSIFFLAGS: + RAL_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + rt2560_init_locked(sc); + startall = 1; + } else + rt2560_update_promisc(ic); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rt2560_stop_locked(sc); + } + RAL_UNLOCK(sc); + 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 @@ -2047,7 +2101,8 @@ rt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) static void rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint8_t power, tmp; u_int i, chan; @@ -2146,7 +2201,8 @@ rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) static void rt2560_set_channel(struct ieee80211com *ic) { - struct rt2560_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2560_softc *sc = ifp->if_softc; RAL_LOCK(sc); rt2560_set_chan(sc, ic->ic_curchan); @@ -2182,7 +2238,8 @@ rt2560_disable_rf_tune(struct rt2560_softc *sc) static void rt2560_enable_tsf_sync(struct rt2560_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); uint16_t logcwmin, preload; uint32_t tmp; @@ -2223,7 +2280,8 @@ rt2560_enable_tsf(struct rt2560_softc *sc) static void rt2560_update_plcp(struct rt2560_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; /* no short preamble for 1Mbps */ RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); @@ -2302,7 +2360,8 @@ rt2560_set_basicrates(struct rt2560_softc *sc, const struct ieee80211_rateset *rs) { #define RV(r) ((r) & IEEE80211_RATE_VAL) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t mask = 0; uint8_t rate; int i; @@ -2347,7 +2406,7 @@ rt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) } static void -rt2560_set_macaddr(struct rt2560_softc *sc, const uint8_t *addr) +rt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) { uint32_t tmp; @@ -2385,13 +2444,13 @@ rt2560_update_promisc(struct ieee80211com *ic) tmp = RAL_READ(sc, RT2560_RXCSR0); tmp &= ~RT2560_DROP_NOT_TO_ME; - if (ic->ic_promisc == 0) + if (!(ic->ic_ifp->if_flags & IFF_PROMISC)) tmp |= RT2560_DROP_NOT_TO_ME; RAL_WRITE(sc, RT2560_RXCSR0, tmp); DPRINTF(sc, "%s promiscuous mode\n", - (ic->ic_promisc > 0) ? "entering" : "leaving"); + (ic->ic_ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); } static const char * @@ -2457,17 +2516,19 @@ rt2560_read_config(struct rt2560_softc *sc) static void rt2560_scan_start(struct ieee80211com *ic) { - struct rt2560_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2560_softc *sc = ifp->if_softc; /* abort TSF synchronization */ RAL_WRITE(sc, RT2560_CSR14, 0); - rt2560_set_bssid(sc, ieee80211broadcastaddr); + rt2560_set_bssid(sc, ifp->if_broadcastaddr); } static void rt2560_scan_end(struct ieee80211com *ic) { - struct rt2560_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2560_softc *sc = ifp->if_softc; struct ieee80211vap *vap = ic->ic_scan->ss_vap; rt2560_enable_tsf_sync(sc); @@ -2561,8 +2622,8 @@ static void rt2560_init_locked(struct rt2560_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; int i; @@ -2593,7 +2654,7 @@ rt2560_init_locked(struct rt2560_softc *sc) for (i = 0; i < N(rt2560_def_mac); i++) RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); - rt2560_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + rt2560_set_macaddr(sc, IF_LLADDR(ifp)); /* set basic rate set (will be updated later) */ RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); @@ -2623,7 +2684,7 @@ rt2560_init_locked(struct rt2560_softc *sc) if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_MBSS) tmp |= RT2560_DROP_TODS; - if (ic->ic_promisc == 0) + if (!(ifp->if_flags & IFF_PROMISC)) tmp |= RT2560_DROP_NOT_TO_ME; } RAL_WRITE(sc, RT2560_RXCSR0, tmp); @@ -2638,7 +2699,8 @@ rt2560_init_locked(struct rt2560_softc *sc) /* enable interrupts */ RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); - sc->sc_flags |= RT2560_F_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); #undef N @@ -2648,19 +2710,21 @@ static void rt2560_init(void *priv) { struct rt2560_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; RAL_LOCK(sc); rt2560_init_locked(sc); RAL_UNLOCK(sc); - if (sc->sc_flags & RT2560_F_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); /* start all vap's */ } static void rt2560_stop_locked(struct rt2560_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; volatile int *flags = &sc->sc_flags; RAL_LOCK_ASSERT(sc); @@ -2671,8 +2735,8 @@ rt2560_stop_locked(struct rt2560_softc *sc) callout_stop(&sc->watchdog_ch); sc->sc_tx_timer = 0; - if (sc->sc_flags & RT2560_F_RUNNING) { - sc->sc_flags &= ~RT2560_F_RUNNING; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* abort Tx */ RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); @@ -2694,6 +2758,7 @@ rt2560_stop_locked(struct rt2560_softc *sc) rt2560_reset_tx_ring(sc, &sc->bcnq); rt2560_reset_rx_ring(sc, &sc->rxq); } + sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); } void @@ -2711,24 +2776,29 @@ rt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct rt2560_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2560_softc *sc = ifp->if_softc; RAL_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & RT2560_F_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return ENETDOWN; } if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + sc->sc_flags |= RT2560_F_PRIO_OACTIVE; RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return ENOBUFS; /* XXX */ } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if (params == NULL) { /* * Legacy path; interpret frame contents to decide @@ -2750,6 +2820,7 @@ rt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return 0; bad: + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); RAL_UNLOCK(sc); return EIO; /* XXX */ diff --git a/sys/dev/ral/rt2560var.h b/sys/dev/ral/rt2560var.h index 3a5fef9..b6a8d68 100644 --- a/sys/dev/ral/rt2560var.h +++ b/sys/dev/ral/rt2560var.h @@ -105,13 +105,13 @@ struct rt2560_vap { #define RT2560_VAP(vap) ((struct rt2560_vap *)(vap)) struct rt2560_softc { - struct ieee80211com sc_ic; - struct mtx sc_mtx; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; + struct mtx sc_mtx; + struct callout watchdog_ch; int sc_tx_timer; @@ -152,7 +152,8 @@ struct rt2560_softc { struct rt2560_tx_radiotap_header sc_txtap; int sc_txtap_len; #define RT2560_F_INPUT_RUNNING 0x1 -#define RT2560_F_RUNNING 0x2 +#define RT2560_F_PRIO_OACTIVE 0x2 +#define RT2560_F_DATA_OACTIVE 0x4 int sc_flags; }; diff --git a/sys/dev/ral/rt2661.c b/sys/dev/ral/rt2661.c index c77d4f8..15a2364 100644 --- a/sys/dev/ral/rt2661.c +++ b/sys/dev/ral/rt2661.c @@ -121,12 +121,12 @@ static int rt2661_tx_data(struct rt2661_softc *, struct mbuf *, struct ieee80211_node *, int); static int rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *, struct ieee80211_node *); -static int rt2661_transmit(struct ieee80211com *, struct mbuf *); -static void rt2661_start(struct rt2661_softc *); +static void rt2661_start_locked(struct ifnet *); +static void rt2661_start(struct ifnet *); static int rt2661_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void rt2661_watchdog(void *); -static void rt2661_parent(struct ieee80211com *); +static int rt2661_ioctl(struct ifnet *, u_long, caddr_t); static void rt2661_bbp_write(struct rt2661_softc *, uint8_t, uint8_t); static uint8_t rt2661_bbp_read(struct rt2661_softc *, uint8_t); @@ -197,19 +197,27 @@ int rt2661_attach(device_t dev, int id) { struct rt2661_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; uint32_t val; int error, ac, ntries; uint8_t bands; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_id = id; sc->sc_dev = dev; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + return ENOMEM; + } + ic = ifp->if_l2com; + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* wait for NIC to initialize */ for (ntries = 0; ntries < 1000; ntries++) { @@ -225,7 +233,7 @@ rt2661_attach(device_t dev, int id) } /* retrieve RF rev. no and various other things from EEPROM */ - rt2661_read_eeprom(sc, ic->ic_macaddr); + rt2661_read_eeprom(sc, macaddr); device_printf(dev, "MAC/BBP RT%X, RF %s\n", val, rt2661_get_rf(sc->rf_rev)); @@ -255,6 +263,17 @@ rt2661_attach(device_t dev, int id) goto fail3; } + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rt2661_init; + ifp->if_ioctl = rt2661_ioctl; + ifp->if_start = rt2661_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(dev); ic->ic_opmode = IEEE80211_M_STA; @@ -286,7 +305,7 @@ rt2661_attach(device_t dev, int id) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); #if 0 ic->ic_wme.wme_update = rt2661_wme_update; #endif @@ -296,8 +315,7 @@ rt2661_attach(device_t dev, int id) ic->ic_updateslot = rt2661_update_slot; ic->ic_update_promisc = rt2661_update_promisc; ic->ic_raw_xmit = rt2661_raw_xmit; - ic->ic_transmit = rt2661_transmit; - ic->ic_parent = rt2661_parent; + ic->ic_vap_create = rt2661_vap_create; ic->ic_vap_delete = rt2661_vap_delete; @@ -321,6 +339,7 @@ fail3: rt2661_free_tx_ring(sc, &sc->mgtq); fail2: while (--ac >= 0) rt2661_free_tx_ring(sc, &sc->txq[ac]); fail1: mtx_destroy(&sc->sc_mtx); + if_free(ifp); return error; } @@ -328,14 +347,14 @@ int rt2661_detach(void *xsc) { struct rt2661_softc *sc = xsc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; RAL_LOCK(sc); rt2661_stop_locked(sc); RAL_UNLOCK(sc); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); rt2661_free_tx_ring(sc, &sc->txq[0]); rt2661_free_tx_ring(sc, &sc->txq[1]); @@ -344,6 +363,8 @@ rt2661_detach(void *xsc) rt2661_free_tx_ring(sc, &sc->mgtq); rt2661_free_rx_ring(sc, &sc->rxq); + if_free(ifp); + mtx_destroy(&sc->sc_mtx); return 0; @@ -355,7 +376,7 @@ rt2661_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct rt2661_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; struct rt2661_vap *rvp; struct ieee80211vap *vap; @@ -368,7 +389,7 @@ rt2661_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_MBSS: /* XXXRP: TBD */ if (!TAILQ_EMPTY(&ic->ic_vaps)) { - device_printf(sc->sc_dev, "only 1 vap supported\n"); + if_printf(ifp, "only 1 vap supported\n"); return NULL; } if (opmode == IEEE80211_M_STA) @@ -377,8 +398,7 @@ rt2661_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_WDS: if (TAILQ_EMPTY(&ic->ic_vaps) || ic->ic_opmode != IEEE80211_M_HOSTAP) { - device_printf(sc->sc_dev, - "wds only supported in ap mode\n"); + if_printf(ifp, "wds only supported in ap mode\n"); return NULL; } /* @@ -389,12 +409,15 @@ rt2661_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, flags &= ~IEEE80211_CLONE_BSSID; break; default: - device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); + if_printf(ifp, "unknown opmode %d\n", opmode); return NULL; } - rvp = malloc(sizeof(struct rt2661_vap), M_80211_VAP, M_WAITOK | M_ZERO); + rvp = (struct rt2661_vap *) malloc(sizeof(struct rt2661_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return NULL; vap = &rvp->ral_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override state transition machine */ rvp->ral_newstate = vap->iv_newstate; @@ -405,8 +428,7 @@ rt2661_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); if (TAILQ_FIRST(&ic->ic_vaps) == vap) ic->ic_opmode = opmode; return vap; @@ -442,8 +464,9 @@ void rt2661_resume(void *xsc) { struct rt2661_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; - if (sc->sc_ic.ic_nrunning > 0) + if (ifp->if_flags & IFF_UP) rt2661_init(sc); } @@ -747,7 +770,7 @@ rt2661_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct rt2661_vap *rvp = RT2661_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct rt2661_softc *sc = ic->ic_softc; + struct rt2661_softc *sc = ic->ic_ifp->if_softc; int error; if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { @@ -846,10 +869,11 @@ rt2661_eeprom_read(struct rt2661_softc *sc, uint8_t addr) static void rt2661_tx_intr(struct rt2661_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct rt2661_tx_ring *txq; struct rt2661_tx_data *data; uint32_t val; - int error, qid, retrycnt; + int qid, retrycnt; struct ieee80211vap *vap; for (;;) { @@ -887,7 +911,7 @@ rt2661_tx_intr(struct rt2661_softc *sc) ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &retrycnt, NULL); - error = 0; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); break; case RT2661_TX_RETRY_FAIL: @@ -899,14 +923,14 @@ rt2661_tx_intr(struct rt2661_softc *sc) ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &retrycnt, NULL); - error = 1; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; default: /* other failure */ device_printf(sc->sc_dev, "sending data frame failed 0x%08x\n", val); - error = 1; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } DPRINTFN(sc, 15, "tx done q=%d idx=%u\n", qid, txq->stat); @@ -915,12 +939,17 @@ rt2661_tx_intr(struct rt2661_softc *sc) if (++txq->stat >= txq->count) /* faster than % count */ txq->stat = 0; - ieee80211_tx_complete(ni, m, error); + if (m->m_flags & M_TXCB) + ieee80211_process_callback(ni, m, + RT2661_TX_RESULT(val) != RT2661_TX_SUCCESS); + m_freem(m); + ieee80211_free_node(ni); } sc->sc_tx_timer = 0; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - rt2661_start(sc); + rt2661_start_locked(ifp); } static void @@ -958,7 +987,8 @@ rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2661_tx_ring *txq) static void rt2661_rx_intr(struct rt2661_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rt2661_rx_desc *desc; struct rt2661_rx_data *data; bus_addr_t physaddr; @@ -987,12 +1017,12 @@ rt2661_rx_intr(struct rt2661_softc *sc) */ DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", le32toh(desc->flags)); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } if ((le32toh(desc->flags) & RT2661_RX_CIPHER_MASK) != 0) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1005,7 +1035,7 @@ rt2661_rx_intr(struct rt2661_softc *sc) */ mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (mnew == NULL) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1028,7 +1058,7 @@ rt2661_rx_intr(struct rt2661_softc *sc) panic("%s: could not load old rx mbuf", device_get_name(sc->sc_dev)); } - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1041,6 +1071,7 @@ rt2661_rx_intr(struct rt2661_softc *sc) desc->physaddr = htole32(physaddr); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff; @@ -1125,6 +1156,7 @@ void rt2661_intr(void *arg) { struct rt2661_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t r1, r2; RAL_LOCK(sc); @@ -1134,7 +1166,7 @@ rt2661_intr(void *arg) RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0xffffffff); /* don't re-enable interrupts if we're shutting down */ - if (!(sc->sc_flags & RAL_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RAL_UNLOCK(sc); return; } @@ -1210,7 +1242,8 @@ rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc, uint32_t flags, uint16_t xflags, int len, int rate, const bus_dma_segment_t *segs, int nsegs, int ac) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t plcp_length; int i, remainder; @@ -1428,7 +1461,8 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, int ac) { struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rt2661_tx_ring *txq = &sc->txq[ac]; struct rt2661_tx_desc *desc; struct rt2661_tx_data *data; @@ -1570,31 +1604,10 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0, return 0; } -static int -rt2661_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct rt2661_softc *sc = ic->ic_softc; - int error; - - RAL_LOCK(sc); - if ((sc->sc_flags & RAL_RUNNING) == 0) { - RAL_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RAL_UNLOCK(sc); - return (error); - } - rt2661_start(sc); - RAL_UNLOCK(sc); - - return (0); -} - static void -rt2661_start(struct rt2661_softc *sc) +rt2661_start_locked(struct ifnet *ifp) { + struct rt2661_softc *sc = ifp->if_softc; struct mbuf *m; struct ieee80211_node *ni; int ac; @@ -1602,50 +1615,69 @@ rt2661_start(struct rt2661_softc *sc) RAL_LOCK_ASSERT(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & RAL_RUNNING) || sc->sc_invalid) + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) || sc->sc_invalid) return; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + ac = M_WME_GETAC(m); if (sc->txq[ac].queued >= RT2661_TX_RING_COUNT - 1) { /* there is no place left in this ring */ - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; if (rt2661_tx_data(sc, m, ni, ac) != 0) { ieee80211_free_node(ni); - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } + sc->sc_tx_timer = 5; } } +static void +rt2661_start(struct ifnet *ifp) +{ + struct rt2661_softc *sc = ifp->if_softc; + + RAL_LOCK(sc); + rt2661_start_locked(ifp); + RAL_UNLOCK(sc); +} + static int rt2661_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct rt2661_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2661_softc *sc = ifp->if_softc; RAL_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & RAL_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return ENETDOWN; } if (sc->mgtq.queued >= RT2661_MGT_RING_COUNT) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return ENOBUFS; /* XXX */ } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + /* * Legacy path; interpret frame contents to decide * precisely how to send the frame. @@ -1659,6 +1691,7 @@ rt2661_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return 0; bad: + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); RAL_UNLOCK(sc); return EIO; /* XXX */ @@ -1668,42 +1701,61 @@ static void rt2661_watchdog(void *arg) { struct rt2661_softc *sc = (struct rt2661_softc *)arg; + struct ifnet *ifp = sc->sc_ifp; RAL_LOCK_ASSERT(sc); - KASSERT(sc->sc_flags & RAL_RUNNING, ("not running")); + KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); if (sc->sc_invalid) /* card ejected */ return; if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); + if_printf(ifp, "device timeout\n"); rt2661_init_locked(sc); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* NB: callout is reset in rt2661_init() */ return; } callout_reset(&sc->watchdog_ch, hz, rt2661_watchdog, sc); } -static void -rt2661_parent(struct ieee80211com *ic) +static int +rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct rt2661_softc *sc = ic->ic_softc; - int startall = 0; + struct rt2661_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; - RAL_LOCK(sc); - if (ic->ic_nrunning > 0) { - if ((sc->sc_flags & RAL_RUNNING) == 0) { - rt2661_init_locked(sc); - startall = 1; - } else - rt2661_update_promisc(ic); - } else if (sc->sc_flags & RAL_RUNNING) - rt2661_stop_locked(sc); - RAL_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + switch (cmd) { + case SIOCSIFFLAGS: + RAL_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + rt2661_init_locked(sc); + startall = 1; + } else + rt2661_update_promisc(ic); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rt2661_stop_locked(sc); + } + RAL_UNLOCK(sc); + 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 @@ -1827,7 +1879,8 @@ rt2661_select_antenna(struct rt2661_softc *sc) static void rt2661_enable_mrr(struct rt2661_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = RAL_READ(sc, RT2661_TXRX_CSR4); @@ -1843,7 +1896,8 @@ rt2661_enable_mrr(struct rt2661_softc *sc) static void rt2661_set_txpreamble(struct rt2661_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = RAL_READ(sc, RT2661_TXRX_CSR4); @@ -1860,7 +1914,8 @@ rt2661_set_basicrates(struct rt2661_softc *sc, const struct ieee80211_rateset *rs) { #define RV(r) ((r) & IEEE80211_RATE_VAL) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t mask = 0; uint8_t rate; int i; @@ -1929,7 +1984,8 @@ rt2661_select_band(struct rt2661_softc *sc, struct ieee80211_channel *c) static void rt2661_set_chan(struct rt2661_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct rfprog *rfprog; uint8_t bbp3, bbp94 = RT2661_BBPR94_DEFAULT; int8_t power; @@ -2032,13 +2088,13 @@ rt2661_update_promisc(struct ieee80211com *ic) tmp = RAL_READ(sc, RT2661_TXRX_CSR0); tmp &= ~RT2661_DROP_NOT_TO_ME; - if (ic->ic_promisc == 0) + if (!(ic->ic_ifp->if_flags & IFF_PROMISC)) tmp |= RT2661_DROP_NOT_TO_ME; RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp); DPRINTF(sc, "%s promiscuous mode\n", - (ic->ic_promisc > 0) ? "entering" : "leaving"); + (ic->ic_ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); } /* @@ -2047,7 +2103,7 @@ rt2661_update_promisc(struct ieee80211com *ic) static int rt2661_wme_update(struct ieee80211com *ic) { - struct rt2661_softc *sc = ic->ic_softc; + struct rt2661_softc *sc = ic->ic_ifp->if_softc; const struct wmeParams *wmep; wmep = ic->ic_wme.wme_chanParams.cap_wmeParams; @@ -2245,8 +2301,8 @@ static void rt2661_init_locked(struct rt2661_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp, sta[3]; int i, error, ntries; @@ -2255,7 +2311,7 @@ rt2661_init_locked(struct rt2661_softc *sc) if ((sc->sc_flags & RAL_FW_LOADED) == 0) { error = rt2661_load_microcode(sc); if (error != 0) { - device_printf(sc->sc_dev, + if_printf(ifp, "%s: could not load 8051 microcode, error %d\n", __func__, error); return; @@ -2308,7 +2364,7 @@ rt2661_init_locked(struct rt2661_softc *sc) for (i = 0; i < N(rt2661_def_mac); i++) RAL_WRITE(sc, rt2661_def_mac[i].reg, rt2661_def_mac[i].val); - rt2661_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + rt2661_set_macaddr(sc, IF_LLADDR(ifp)); /* set host ready */ RAL_WRITE(sc, RT2661_MAC_CSR1, 3); @@ -2347,7 +2403,7 @@ rt2661_init_locked(struct rt2661_softc *sc) if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_MBSS) tmp |= RT2661_DROP_TODS; - if (ic->ic_promisc == 0) + if (!(ifp->if_flags & IFF_PROMISC)) tmp |= RT2661_DROP_NOT_TO_ME; } @@ -2369,7 +2425,8 @@ rt2661_init_locked(struct rt2661_softc *sc) /* kick Rx */ RAL_WRITE(sc, RT2661_RX_CNTL_CSR, 1); - sc->sc_flags |= RAL_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->watchdog_ch, hz, rt2661_watchdog, sc); #undef N @@ -2379,21 +2436,23 @@ static void rt2661_init(void *priv) { struct rt2661_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; RAL_LOCK(sc); rt2661_init_locked(sc); RAL_UNLOCK(sc); - if (sc->sc_flags & RAL_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); /* start all vap's */ } void rt2661_stop_locked(struct rt2661_softc *sc) { - volatile int *flags = &sc->sc_flags; + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; + volatile int *flags = &sc->sc_flags; while (*flags & RAL_INPUT_RUNNING) msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); @@ -2401,8 +2460,8 @@ rt2661_stop_locked(struct rt2661_softc *sc) callout_stop(&sc->watchdog_ch); sc->sc_tx_timer = 0; - if (sc->sc_flags & RAL_RUNNING) { - sc->sc_flags &= ~RAL_RUNNING; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* abort Tx (for all 5 Tx rings) */ RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 0x1f << 16); @@ -2446,6 +2505,7 @@ rt2661_stop(void *priv) static int rt2661_load_microcode(struct rt2661_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; const struct firmware *fp; const char *imagename; int ntries, error; @@ -2457,7 +2517,7 @@ rt2661_load_microcode(struct rt2661_softc *sc) case 0x0302: imagename = "rt2561fw"; break; case 0x0401: imagename = "rt2661fw"; break; default: - device_printf(sc->sc_dev, "%s: unexpected pci device id 0x%x, " + if_printf(ifp, "%s: unexpected pci device id 0x%x, " "don't know how to retrieve firmware\n", __func__, sc->sc_id); return EINVAL; @@ -2466,8 +2526,7 @@ rt2661_load_microcode(struct rt2661_softc *sc) fp = firmware_get(imagename); RAL_LOCK(sc); if (fp == NULL) { - device_printf(sc->sc_dev, - "%s: unable to retrieve firmware image %s\n", + if_printf(ifp, "%s: unable to retrieve firmware image %s\n", __func__, imagename); return EINVAL; } @@ -2498,8 +2557,8 @@ rt2661_load_microcode(struct rt2661_softc *sc) DELAY(100); } if (ntries == 500) { - device_printf(sc->sc_dev, - "%s: timeout waiting for MCU to initialize\n", __func__); + if_printf(ifp, "%s: timeout waiting for MCU to initialize\n", + __func__); error = EIO; } else error = 0; @@ -2667,7 +2726,8 @@ rt2661_prepare_beacon(struct rt2661_softc *sc, struct ieee80211vap *vap) static void rt2661_enable_tsf_sync(struct rt2661_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); uint32_t tmp; @@ -2751,19 +2811,21 @@ rt2661_get_rssi(struct rt2661_softc *sc, uint8_t raw) static void rt2661_scan_start(struct ieee80211com *ic) { - struct rt2661_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2661_softc *sc = ifp->if_softc; uint32_t tmp; /* abort TSF synchronization */ tmp = RAL_READ(sc, RT2661_TXRX_CSR9); RAL_WRITE(sc, RT2661_TXRX_CSR9, tmp & ~0xffffff); - rt2661_set_bssid(sc, ieee80211broadcastaddr); + rt2661_set_bssid(sc, ifp->if_broadcastaddr); } static void rt2661_scan_end(struct ieee80211com *ic) { - struct rt2661_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2661_softc *sc = ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); rt2661_enable_tsf_sync(sc); @@ -2774,7 +2836,8 @@ rt2661_scan_end(struct ieee80211com *ic) static void rt2661_set_channel(struct ieee80211com *ic) { - struct rt2661_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2661_softc *sc = ifp->if_softc; RAL_LOCK(sc); rt2661_set_chan(sc, ic->ic_curchan); diff --git a/sys/dev/ral/rt2661var.h b/sys/dev/ral/rt2661var.h index 7ea16f6..9927d13 100644 --- a/sys/dev/ral/rt2661var.h +++ b/sys/dev/ral/rt2661var.h @@ -97,13 +97,13 @@ struct rt2661_vap { #define RT2661_VAP(vap) ((struct rt2661_vap *)(vap)) struct rt2661_softc { - struct ieee80211com sc_ic; - struct mtx sc_mtx; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; + struct mtx sc_mtx; + struct callout watchdog_ch; int sc_tx_timer; @@ -117,7 +117,6 @@ struct rt2661_softc { int sc_flags; #define RAL_FW_LOADED 0x1 #define RAL_INPUT_RUNNING 0x2 -#define RAL_RUNNING 0x4 int sc_id; struct ieee80211_channel *sc_curchan; diff --git a/sys/dev/ral/rt2860.c b/sys/dev/ral/rt2860.c index b3c737d..782fa1f 100644 --- a/sys/dev/ral/rt2860.c +++ b/sys/dev/ral/rt2860.c @@ -122,10 +122,10 @@ static int rt2860_raw_xmit(struct ieee80211_node *, struct mbuf *, static int rt2860_tx_raw(struct rt2860_softc *, struct mbuf *, struct ieee80211_node *, const struct ieee80211_bpf_params *params); -static int rt2860_transmit(struct ieee80211com *, struct mbuf *); -static void rt2860_start(struct rt2860_softc *); +static void rt2860_start(struct ifnet *); +static void rt2860_start_locked(struct ifnet *); static void rt2860_watchdog(void *); -static void rt2860_parent(struct ieee80211com *); +static int rt2860_ioctl(struct ifnet *, u_long, caddr_t); static void rt2860_mcu_bbp_write(struct rt2860_softc *, uint8_t, uint8_t); static uint8_t rt2860_mcu_bbp_read(struct rt2860_softc *, uint8_t); static void rt2860_rf_write(struct rt2860_softc *, uint8_t, uint32_t); @@ -156,7 +156,7 @@ static void rt2860_set_bssid(struct rt2860_softc *, const uint8_t *); static void rt2860_set_macaddr(struct rt2860_softc *, const uint8_t *); static void rt2860_update_promisc(struct ieee80211com *); static void rt2860_updateslot(struct ieee80211com *); -static void rt2860_updateprot(struct rt2860_softc *); +static void rt2860_updateprot(struct ifnet *); static int rt2860_updateedca(struct ieee80211com *); #ifdef HW_CRYPTO static int rt2860_set_key(struct ieee80211com *, struct ieee80211_node *, @@ -230,19 +230,27 @@ int rt2860_attach(device_t dev, int id) { struct rt2860_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; uint32_t tmp; int error, ntries, qid; uint8_t bands; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; sc->sc_debug = 0; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + return ENOMEM; + } + ic = ifp->if_l2com; + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* wait for NIC to initialize */ for (ntries = 0; ntries < 100; ntries++) { @@ -265,11 +273,11 @@ rt2860_attach(device_t dev, int id) sc->sc_flags |= RT2860_ADVANCED_PS; /* retrieve RF rev. no and various other things from EEPROM */ - rt2860_read_eeprom(sc, ic->ic_macaddr); + rt2860_read_eeprom(sc, macaddr); device_printf(sc->sc_dev, "MAC/BBP RT%X (rev 0x%04X), " "RF %s (MIMO %dT%dR), address %6D\n", sc->mac_ver, sc->mac_rev, rt2860_get_rf(sc->rf_rev), - sc->ntxchains, sc->nrxchains, ic->ic_macaddr, ":"); + sc->ntxchains, sc->nrxchains, macaddr, ":"); /* * Allocate Tx (4 EDCAs + HCCA + Mgt) and Rx rings. @@ -296,6 +304,17 @@ rt2860_attach(device_t dev, int id) sc->mgtqid = (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) ? WME_AC_VO : 5; + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rt2860_init; + ifp->if_ioctl = rt2860_ioctl; + ifp->if_start = rt2860_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(dev); ic->ic_opmode = IEEE80211_M_STA; @@ -326,7 +345,7 @@ rt2860_attach(device_t dev, int id) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_wme.wme_update = rt2860_updateedca; ic->ic_scan_start = rt2860_scan_start; @@ -338,8 +357,7 @@ rt2860_attach(device_t dev, int id) sc->sc_node_free = ic->ic_node_free; ic->ic_node_free = rt2860_node_free; ic->ic_newassoc = rt2860_newassoc; - ic->ic_transmit = rt2860_transmit; - ic->ic_parent = rt2860_parent; + ic->ic_vap_create = rt2860_vap_create; ic->ic_vap_delete = rt2860_vap_delete; @@ -363,6 +381,7 @@ fail3: rt2860_free_rx_ring(sc, &sc->rxq); fail2: while (--qid >= 0) rt2860_free_tx_ring(sc, &sc->txq[qid]); fail1: mtx_destroy(&sc->sc_mtx); + if_free(ifp); return error; } @@ -370,7 +389,8 @@ int rt2860_detach(void *xsc) { struct rt2860_softc *sc = xsc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int qid; RAL_LOCK(sc); @@ -378,12 +398,14 @@ rt2860_detach(void *xsc) RAL_UNLOCK(sc); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + for (qid = 0; qid < 6; qid++) rt2860_free_tx_ring(sc, &sc->txq[qid]); rt2860_free_rx_ring(sc, &sc->rxq); rt2860_free_tx_pool(sc); + if_free(ifp); + mtx_destroy(&sc->sc_mtx); return 0; @@ -409,8 +431,9 @@ void rt2860_resume(void *xsc) { struct rt2860_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; - if (sc->sc_ic.ic_nrunning > 0) + if (ifp->if_flags & IFF_UP) rt2860_init(sc); } @@ -420,7 +443,7 @@ rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct rt2860_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; struct rt2860_vap *rvp; struct ieee80211vap *vap; @@ -433,7 +456,7 @@ rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_MBSS: /* XXXRP: TBD */ if (!TAILQ_EMPTY(&ic->ic_vaps)) { - device_printf(sc->sc_dev, "only 1 vap supported\n"); + if_printf(ifp, "only 1 vap supported\n"); return NULL; } if (opmode == IEEE80211_M_STA) @@ -442,8 +465,7 @@ rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, case IEEE80211_M_WDS: if (TAILQ_EMPTY(&ic->ic_vaps) || ic->ic_opmode != IEEE80211_M_HOSTAP) { - device_printf(sc->sc_dev, - "wds only supported in ap mode\n"); + if_printf(ifp, "wds only supported in ap mode\n"); return NULL; } /* @@ -454,12 +476,14 @@ rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, flags &= ~IEEE80211_CLONE_BSSID; break; default: - device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); + if_printf(ifp, "unknown opmode %d\n", opmode); return NULL; } - rvp = malloc(sizeof(struct rt2860_vap), M_80211_VAP, M_WAITOK | M_ZERO); + rvp = malloc(sizeof(struct rt2860_vap), M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return NULL; vap = &rvp->ral_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override state transition machine */ rvp->ral_newstate = vap->iv_newstate; @@ -473,8 +497,7 @@ rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); if (TAILQ_FIRST(&ic->ic_vaps) == vap) ic->ic_opmode = opmode; return vap; @@ -806,7 +829,7 @@ rt2860_free_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring) static void rt2860_updatestats(struct rt2860_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* * In IBSS or HostAP modes (when the hardware sends beacons), the @@ -833,7 +856,7 @@ static void rt2860_newassoc(struct ieee80211_node *ni, int isnew) { struct ieee80211com *ic = ni->ni_ic; - struct rt2860_softc *sc = ic->ic_softc; + struct rt2860_softc *sc = ic->ic_ifp->if_softc; uint8_t wcid; wcid = IEEE80211_AID(ni->ni_associd); @@ -852,7 +875,7 @@ static void rt2860_node_free(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct rt2860_softc *sc = ic->ic_softc; + struct rt2860_softc *sc = ic->ic_ifp->if_softc; uint8_t wcid; if (ni->ni_associd != 0) { @@ -900,7 +923,7 @@ rt2860_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct rt2860_vap *rvp = RT2860_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct rt2860_softc *sc = ic->ic_softc; + struct rt2860_softc *sc = ic->ic_ifp->if_softc; uint32_t tmp; int error; @@ -1078,6 +1101,7 @@ rt2860_intr_coherent(struct rt2860_softc *sc) static void rt2860_drain_stats_fifo(struct rt2860_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_node *ni; uint32_t stat; int retrycnt; @@ -1113,8 +1137,7 @@ rt2860_drain_stats_fifo(struct rt2860_softc *sc) } else { ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &retrycnt, NULL); - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } } } @@ -1122,6 +1145,7 @@ rt2860_drain_stats_fifo(struct rt2860_softc *sc) static void rt2860_tx_intr(struct rt2860_softc *sc, int qid) { + struct ifnet *ifp = sc->sc_ifp; struct rt2860_tx_ring *ring = &sc->txq[qid]; uint32_t hw; @@ -1139,11 +1163,15 @@ rt2860_tx_intr(struct rt2860_softc *sc, int qid) ieee80211_process_callback(data->ni, data->m, 0); } - ieee80211_tx_complete(data->ni, data->m, 0); - data->ni = NULL; + m_freem(data->m); + ieee80211_free_node(data->ni); data->m = NULL; + data->ni = NULL; + SLIST_INSERT_HEAD(&sc->data_pool, data, next); ring->data[ring->next] = NULL; + + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } ring->queued--; ring->next = (ring->next + 1) % RT2860_TX_RING_COUNT; @@ -1152,7 +1180,8 @@ rt2860_tx_intr(struct rt2860_softc *sc, int qid) sc->sc_tx_timer = 0; if (ring->queued < RT2860_TX_RING_COUNT) sc->qfullmsk &= ~(1 << qid); - rt2860_start(sc); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + rt2860_start_locked(ifp); } /* @@ -1177,7 +1206,8 @@ static void rt2860_rx_intr(struct rt2860_softc *sc) { struct rt2860_rx_radiotap_header *tap; - 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, *m1; @@ -1204,7 +1234,7 @@ rt2860_rx_intr(struct rt2860_softc *sc) if (__predict_false(rxd->flags & htole32(RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1213,14 +1243,14 @@ rt2860_rx_intr(struct rt2860_softc *sc) /* report MIC failures to net80211 for TKIP */ ic->ic_stats.is_rx_locmicfail++; ieee80211_michael_mic_failure(ic, 0/* XXX */); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } #endif m1 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (__predict_false(m1 == NULL)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1244,7 +1274,7 @@ rt2860_rx_intr(struct rt2860_softc *sc) } /* physical address may have changed */ rxd->sdp0 = htole32(physaddr); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto skip; } @@ -1259,6 +1289,7 @@ rt2860_rx_intr(struct rt2860_softc *sc) rxwi = mtod(m, struct rt2860_rxwi *); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_data = (caddr_t)(rxwi + 1); m->m_pkthdr.len = m->m_len = le16toh(rxwi->len) & 0xfff; @@ -1368,7 +1399,7 @@ rt2860_tbtt_intr(struct rt2860_softc *sc) #endif /* check if protection mode has changed */ if ((sc->sc_ic_flags ^ ic->ic_flags) & IEEE80211_F_USEPROT) { - rt2860_updateprot(sc); + rt2860_updateprot(ic); sc->sc_ic_flags = ic->ic_flags; } #endif @@ -1377,7 +1408,7 @@ rt2860_tbtt_intr(struct rt2860_softc *sc) static void rt2860_gp_intr(struct rt2860_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); DPRINTFN(2, ("GP timeout state=%d\n", vap->iv_state)); @@ -1449,7 +1480,8 @@ rt2860_intr(void *arg) static int rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct rt2860_tx_ring *ring; struct rt2860_tx_data *data; @@ -1693,13 +1725,14 @@ rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct rt2860_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2860_softc *sc = ifp->if_softc; int error; RAL_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & RT2860_RUNNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); @@ -1721,6 +1754,7 @@ rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if (error != 0) { /* NB: m is reclaimed on tx failure */ ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } sc->sc_tx_timer = 5; RAL_UNLOCK(sc); @@ -1731,7 +1765,8 @@ static int rt2860_tx_raw(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct rt2860_tx_ring *ring; struct rt2860_tx_data *data; @@ -1938,46 +1973,41 @@ rt2860_tx_raw(struct rt2860_softc *sc, struct mbuf *m, return 0; } -static int -rt2860_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +rt2860_start(struct ifnet *ifp) { - struct rt2860_softc *sc = ic->ic_softc; - int error; + struct rt2860_softc *sc = ifp->if_softc; RAL_LOCK(sc); - if ((sc->sc_flags & RT2860_RUNNNING) == 0) { - RAL_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RAL_UNLOCK(sc); - return (error); - } - rt2860_start(sc); + rt2860_start_locked(ifp); RAL_UNLOCK(sc); - - return (0); } static void -rt2860_start(struct rt2860_softc *sc) +rt2860_start_locked(struct ifnet *ifp) { + struct rt2860_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; RAL_LOCK_ASSERT(sc); - if ((sc->sc_flags & RT2860_RUNNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) return; - while (!SLIST_EMPTY(&sc->data_pool) && sc->qfullmsk == 0 && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + if (SLIST_EMPTY(&sc->data_pool) || sc->qfullmsk != 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (rt2860_tx(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } sc->sc_tx_timer = 5; @@ -1988,42 +2018,61 @@ static void rt2860_watchdog(void *arg) { struct rt2860_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; RAL_LOCK_ASSERT(sc); - KASSERT(sc->sc_flags & RT2860_RUNNNING, ("not running")); + KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); if (sc->sc_invalid) /* card ejected */ return; if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); + if_printf(ifp, "device timeout\n"); rt2860_stop_locked(sc); rt2860_init_locked(sc); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return; } callout_reset(&sc->watchdog_ch, hz, rt2860_watchdog, sc); } -static void -rt2860_parent(struct ieee80211com *ic) +static int +rt2860_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct rt2860_softc *sc = ic->ic_softc; - int startall = 0; + struct rt2860_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0, startall = 0; - RAL_LOCK(sc); - if (ic->ic_nrunning> 0) { - if (!(sc->sc_flags & RT2860_RUNNNING)) { - rt2860_init_locked(sc); - startall = 1; - } else - rt2860_update_promisc(ic); - } else if (sc->sc_flags & RT2860_RUNNNING) - rt2860_stop_locked(sc); - RAL_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + switch (cmd) { + case SIOCSIFFLAGS: + RAL_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + rt2860_init_locked(sc); + startall = 1; + } else + rt2860_update_promisc(ic); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rt2860_stop_locked(sc); + } + RAL_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCSIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + default: + error = EINVAL; + break; + } + return error; } /* @@ -2246,7 +2295,8 @@ rt2860_enable_mrr(struct rt2860_softc *sc) static void rt2860_set_txpreamble(struct rt2860_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = RAL_READ(sc, RT2860_AUTO_RSP_CFG); @@ -2261,7 +2311,8 @@ rt2860_set_basicrates(struct rt2860_softc *sc, const struct ieee80211_rateset *rs) { #define RV(r) ((r) & IEEE80211_RATE_VAL) - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t mask = 0; uint8_t rate; int i; @@ -2282,7 +2333,8 @@ rt2860_set_basicrates(struct rt2860_softc *sc, static void rt2860_scan_start(struct ieee80211com *ic) { - struct rt2860_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2860_softc *sc = ifp->if_softc; uint32_t tmp; tmp = RAL_READ(sc, RT2860_BCN_TIME_CFG); @@ -2295,7 +2347,8 @@ rt2860_scan_start(struct ieee80211com *ic) static void rt2860_scan_end(struct ieee80211com *ic) { - struct rt2860_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2860_softc *sc = ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); if (vap->iv_state == IEEE80211_S_RUN) { @@ -2307,7 +2360,8 @@ rt2860_scan_end(struct ieee80211com *ic) static void rt2860_set_channel(struct ieee80211com *ic) { - struct rt2860_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rt2860_softc *sc = ifp->if_softc; RAL_LOCK(sc); rt2860_switch_chan(sc, ic->ic_curchan); @@ -3059,9 +3113,10 @@ rt2860_updateslot(struct ieee80211com *ic) } static void -rt2860_updateprot(struct rt2860_softc *sc) +rt2860_updateprot(struct ifnet *ifp) { - struct ieee80211com *ic = &sc->sc_ic; + struct rt2860_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; @@ -3090,7 +3145,7 @@ rt2860_update_promisc(struct ieee80211com *ic) tmp = RAL_READ(sc, RT2860_RX_FILTR_CFG); tmp &= ~RT2860_DROP_NOT_MYBSS; - if (ic->ic_promisc == 0) + if (!(ic->ic_ifp->if_flags & IFF_PROMISC)) tmp |= RT2860_DROP_NOT_MYBSS; RAL_WRITE(sc, RT2860_RX_FILTR_CFG, tmp); } @@ -3098,7 +3153,7 @@ rt2860_update_promisc(struct ieee80211com *ic) static int rt2860_updateedca(struct ieee80211com *ic) { - struct rt2860_softc *sc = ic->ic_softc; + struct rt2860_softc *sc = ic->ic_ifp->if_softc; const struct wmeParams *wmep; int aci; @@ -3270,7 +3325,8 @@ rt2860_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, static int8_t rt2860_rssi2dbm(struct rt2860_softc *sc, uint8_t rssi, uint8_t rxchain) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_channel *c = ic->ic_curchan; int delta; @@ -3745,7 +3801,8 @@ rt5390_bbp_init(struct rt2860_softc *sc) static int rt2860_txrx_enable(struct rt2860_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; int ntries; @@ -3791,21 +3848,22 @@ static void rt2860_init(void *arg) { struct rt2860_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; RAL_LOCK(sc); rt2860_init_locked(sc); RAL_UNLOCK(sc); - if (sc->sc_flags & RT2860_RUNNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); } static void rt2860_init_locked(struct rt2860_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; uint8_t bbp1, bbp3; int i, qid, ridx, ntries, error; @@ -3841,7 +3899,7 @@ rt2860_init_locked(struct rt2860_softc *sc) return; } - rt2860_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + rt2860_set_macaddr(sc, IF_LLADDR(ifp)); /* init Tx power for all Tx rates (from EEPROM) */ for (ridx = 0; ridx < 5; ridx++) { @@ -4038,7 +4096,7 @@ rt2860_init_locked(struct rt2860_softc *sc) RAL_WRITE(sc, RT2860_TX_RTS_CFG, tmp); /* setup initial protection mode */ - rt2860_updateprot(sc); + rt2860_updateprot(ifp); /* turn radio LED on */ rt2860_set_leds(sc, RT2860_LED_RADIO); @@ -4057,7 +4115,8 @@ rt2860_init_locked(struct rt2860_softc *sc) if (sc->sc_flags & RT2860_ADVANCED_PS) rt2860_mcu_cmd(sc, RT2860_MCU_CMD_PSLEVEL, sc->pslevel, 0); - sc->sc_flags |= RT2860_RUNNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->watchdog_ch, hz, rt2860_watchdog, sc); } @@ -4075,15 +4134,16 @@ rt2860_stop(void *arg) static void rt2860_stop_locked(struct rt2860_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; int qid; - if (sc->sc_flags & RT2860_RUNNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) rt2860_set_leds(sc, 0); /* turn all LEDs off */ callout_stop(&sc->watchdog_ch); sc->sc_tx_timer = 0; - sc->sc_flags &= ~RT2860_RUNNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* disable interrupts */ RAL_WRITE(sc, RT2860_INT_MASK, 0); @@ -4234,7 +4294,8 @@ rt3090_set_rx_antenna(struct rt2860_softc *sc, int aux) static void rt2860_switch_chan(struct rt2860_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; u_int chan, group; chan = ieee80211_chan2ieee(ic, c); @@ -4303,7 +4364,8 @@ rt2860_setup_beacon(struct rt2860_softc *sc, struct ieee80211vap *vap) static void rt2860_enable_tsf_sync(struct rt2860_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); uint32_t tmp; diff --git a/sys/dev/ral/rt2860var.h b/sys/dev/ral/rt2860var.h index 3779e5b..28a3d59 100644 --- a/sys/dev/ral/rt2860var.h +++ b/sys/dev/ral/rt2860var.h @@ -115,13 +115,13 @@ struct rt2860_vap { #define RT2860_VAP(vap) ((struct rt2860_vap *)(vap)) struct rt2860_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; - struct mtx sc_mtx; + struct ifnet *sc_ifp; device_t sc_dev; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; + struct mtx sc_mtx; + struct callout watchdog_ch; int sc_invalid; @@ -139,7 +139,6 @@ struct rt2860_softc { #define RT2860_ENABLED (1 << 0) #define RT2860_ADVANCED_PS (1 << 1) #define RT2860_PCIE (1 << 2) -#define RT2860_RUNNNING (1 << 3) struct ieee80211_node *wcid2ni[RT2860_WCID_MAX]; diff --git a/sys/dev/usb/wlan/if_rsu.c b/sys/dev/usb/wlan/if_rsu.c index 463a9bd..89b8c00 100644 --- a/sys/dev/usb/wlan/if_rsu.c +++ b/sys/dev/usb/wlan/if_rsu.c @@ -187,13 +187,15 @@ static struct mbuf * static void rsu_txeof(struct usb_xfer *, struct rsu_data *); static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void rsu_init(struct rsu_softc *); +static void rsu_init(void *); +static void rsu_init_locked(struct rsu_softc *); static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, struct mbuf *, struct rsu_data *); -static int rsu_transmit(struct ieee80211com *, struct mbuf *); -static void rsu_start(struct rsu_softc *); -static void rsu_parent(struct ieee80211com *); -static void rsu_stop(struct rsu_softc *); +static void rsu_start(struct ifnet *); +static void rsu_start_locked(struct ifnet *); +static int rsu_ioctl(struct ifnet *, u_long, caddr_t); +static void rsu_stop(struct ifnet *, int); +static void rsu_stop_locked(struct ifnet *, int); static void rsu_ms_delay(struct rsu_softc *); static device_method_t rsu_methods[] = { @@ -283,7 +285,8 @@ rsu_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); struct rsu_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; int error; uint8_t iface_index, bands; @@ -295,7 +298,6 @@ rsu_attach(device_t self) MTX_DEF); TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, rsu_calib_task, sc); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* Allocate Tx/Rx buffers. */ error = rsu_alloc_rx_list(sc); @@ -331,9 +333,28 @@ rsu_attach(device_t self) device_printf(self, "could not read ROM\n"); goto fail_rom; } - IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->rom[0x12]); + IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->rom[0x12]); device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut); - + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(self, "cannot allocate interface\n"); + goto fail_ifalloc; + } + ic = ifp->if_l2com; + ifp->if_softc = sc; + if_initname(ifp, "rsu", device_get_unit(self)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rsu_init; + ifp->if_ioctl = rsu_ioctl; + ifp->if_start = rsu_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + ifp->if_capabilities |= IFCAP_RXCSUM; + ifp->if_capenable |= IFCAP_RXCSUM; + ifp->if_hwassist = CSUM_TCP; + + 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. */ @@ -366,7 +387,7 @@ rsu_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 = rsu_raw_xmit; ic->ic_scan_start = rsu_scan_start; ic->ic_scan_end = rsu_scan_end; @@ -374,8 +395,6 @@ rsu_attach(device_t self) ic->ic_vap_create = rsu_vap_create; ic->ic_vap_delete = rsu_vap_delete; ic->ic_update_mcast = rsu_update_mcast; - ic->ic_parent = rsu_parent; - ic->ic_transmit = rsu_transmit; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT, @@ -387,6 +406,7 @@ rsu_attach(device_t self) return (0); +fail_ifalloc: fail_rom: usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); fail_usb: @@ -398,11 +418,10 @@ static int rsu_detach(device_t self) { struct rsu_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - RSU_LOCK(sc); - rsu_stop(sc); - RSU_UNLOCK(sc); + rsu_stop(ifp, 1); usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); ieee80211_ifdetach(ic); @@ -412,7 +431,7 @@ rsu_detach(device_t self) rsu_free_tx_list(sc); rsu_free_rx_list(sc); - mbufq_drain(&sc->sc_snd); + if_free(ifp); mtx_destroy(&sc->sc_mtx); return (0); @@ -452,11 +471,14 @@ rsu_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 rsu_vap), M_80211_VAP, M_WAITOK | M_ZERO); + uvp = (struct rsu_vap *) malloc(sizeof(struct rsu_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (uvp == NULL) + return (NULL); vap = &uvp->vap; if (ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags, bssid) != 0) { + flags, bssid, mac) != 0) { /* out of memory */ free(uvp, M_80211_VAP); return (NULL); @@ -468,7 +490,7 @@ rsu_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); @@ -486,8 +508,9 @@ rsu_vap_delete(struct ieee80211vap *vap) static void rsu_scan_start(struct ieee80211com *ic) { - struct rsu_softc *sc = ic->ic_softc; int error; + struct ifnet *ifp = ic->ic_ifp; + struct rsu_softc *sc = ifp->if_softc; /* Scanning is done by the firmware. */ RSU_LOCK(sc); @@ -653,8 +676,11 @@ rsu_getbuf(struct rsu_softc *sc) RSU_ASSERT_LOCKED(sc); bf = _rsu_getbuf(sc); - if (bf == NULL) + if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; DPRINTF("stop queue\n"); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } return (bf); } @@ -909,7 +935,7 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct rsu_vap *uvp = RSU_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct rsu_softc *sc = ic->ic_softc; + struct rsu_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; struct ieee80211_rateset *rs; enum ieee80211_state ostate; @@ -1007,27 +1033,29 @@ static int rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap) { struct r92s_fw_cmd_sitesurvey cmd; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; memset(&cmd, 0, sizeof(cmd)); - if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->sc_scan_pass == 1) + if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->scan_pass == 1) cmd.active = htole32(1); cmd.limit = htole32(48); - if (sc->sc_scan_pass == 1 && vap->iv_des_nssid > 0) { + if (sc->scan_pass == 1 && vap->iv_des_nssid > 0) { /* Do a directed scan for second pass. */ cmd.ssidlen = htole32(vap->iv_des_ssid[0].len); memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid, vap->iv_des_ssid[0].len); } - DPRINTF("sending site survey command, pass=%d\n", sc->sc_scan_pass); + DPRINTF("sending site survey command, pass=%d\n", sc->scan_pass); return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd))); } static int rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct ndis_wlan_bssid_ex *bss; struct ndis_802_11_fixed_ies *fixed; @@ -1105,7 +1133,8 @@ rsu_disconnect(struct rsu_softc *sc) static void rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_frame *wh; struct ieee80211_channel *c; struct ndis_wlan_bssid_ex *bss; @@ -1136,7 +1165,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) IEEE80211_FC0_SUBTYPE_BEACON; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; USETW(wh->i_dur, 0); - IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr); IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr); *(uint16_t *)wh->i_seq = 0; @@ -1144,6 +1173,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) /* Finalize mbuf. */ m->m_pkthdr.len = m->m_len = pktlen; + m->m_pkthdr.rcvif = ifp; /* Fix the channel. */ c = ieee80211_find_channel_byieee(ic, le32toh(bss->config.dsconfig), @@ -1161,7 +1191,8 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) static void rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) { - 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; struct r92s_event_join_bss *rsp; @@ -1197,7 +1228,8 @@ rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) static void rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) { - 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); DPRINTFN(4, "Rx event code=%d len=%d\n", code, len); @@ -1208,18 +1240,18 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) break; case R92S_EVT_SURVEY_DONE: DPRINTF("site survey pass %d done, found %d BSS\n", - sc->sc_scan_pass, le32toh(*(uint32_t *)buf)); + sc->scan_pass, le32toh(*(uint32_t *)buf)); if (vap->iv_state != IEEE80211_S_SCAN) break; /* Ignore if not scanning. */ - if (sc->sc_scan_pass == 0 && vap->iv_des_nssid != 0) { + if (sc->scan_pass == 0 && vap->iv_des_nssid != 0) { /* Schedule a directed scan for hidden APs. */ - sc->sc_scan_pass = 1; + sc->scan_pass = 1; RSU_UNLOCK(sc); ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); RSU_LOCK(sc); break; } - sc->sc_scan_pass = 0; + sc->scan_pass = 0; break; case R92S_EVT_JOIN_BSS: if (vap->iv_state == IEEE80211_S_AUTH) @@ -1242,7 +1274,7 @@ XXX and disrupts the WLAN traffic. Disable for now. DPRINTF("WPS PBC pushed.\n"); break; case R92S_EVT_FWDBG: - if (vap->iv_ifp->if_flags & IFF_DEBUG) { + if (ifp->if_flags & IFF_DEBUG) { buf[60] = '\0'; printf("FWDBG: %s\n", (char *)buf); } @@ -1309,7 +1341,8 @@ rsu_get_rssi(struct rsu_softc *sc, int rate, void *physt) static struct mbuf * rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_frame *wh; struct r92s_rx_stat *stat; uint32_t rxdw0, rxdw3; @@ -1322,11 +1355,11 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) rxdw3 = le32toh(stat->rxdw3); if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return NULL; } if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return NULL; } @@ -1344,9 +1377,11 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR); if (__predict_false(m == NULL)) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return NULL; } + /* Finalize mbuf. */ + m->m_pkthdr.rcvif = ifp; /* Hardware does Rx TCP checksum offload. */ if (rxdw3 & R92S_RXDW3_TCPCHKVALID) { if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT)) @@ -1444,7 +1479,6 @@ static struct mbuf * rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) { struct rsu_softc *sc = data->sc; - struct ieee80211com *ic = &sc->sc_ic; struct r92s_rx_stat *stat; int len; @@ -1452,7 +1486,7 @@ rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) if (__predict_false(len < sizeof(*stat))) { DPRINTF("xfer too short %d\n", len); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); return (NULL); } /* Determine if it is a firmware C2H event or an 802.11 frame. */ @@ -1469,7 +1503,8 @@ static void rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct rsu_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; @@ -1529,7 +1564,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; @@ -1537,16 +1572,35 @@ tr_setup: } + static void rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data) { + struct rsu_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; + + RSU_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); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static void @@ -1554,7 +1608,7 @@ rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error, uint8_t which) { struct rsu_softc *sc = usbd_xfer_softc(xfer); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; struct rsu_data *data; RSU_ASSERT_LOCKED(sc); @@ -1589,7 +1643,7 @@ tr_setup: rsu_txeof(xfer, data); STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); } - counter_u64_add(ic->ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); @@ -1615,7 +1669,8 @@ static int rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, struct rsu_data *data) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; @@ -1717,75 +1772,82 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, return (0); } -static int -rsu_transmit(struct ieee80211com *ic, struct mbuf *m) +static void +rsu_start(struct ifnet *ifp) { - struct rsu_softc *sc = ic->ic_softc; - int error; + struct rsu_softc *sc = ifp->if_softc; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; RSU_LOCK(sc); - if (!sc->sc_running) { - RSU_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RSU_UNLOCK(sc); - return (error); - } - rsu_start(sc); + rsu_start_locked(ifp); RSU_UNLOCK(sc); - - return (0); } static void -rsu_start(struct rsu_softc *sc) +rsu_start_locked(struct ifnet *ifp) { + struct rsu_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct rsu_data *bf; struct mbuf *m; RSU_ASSERT_LOCKED(sc); - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { - bf = rsu_getbuf(sc); - if (bf == NULL) { - mbufq_prepend(&sc->sc_snd, m); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) break; - } - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; m->m_pkthdr.rcvif = NULL; - if (rsu_tx_start(sc, ni, m, bf) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + bf = rsu_getbuf(sc); + if (bf == NULL) { + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); + m_freem(m); + ieee80211_free_node(ni); + } else if (rsu_tx_start(sc, ni, m, bf) != 0) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); ieee80211_free_node(ni); - break; } } } -static void -rsu_parent(struct ieee80211com *ic) +static int +rsu_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct rsu_softc *sc = ic->ic_softc; - int startall = 0; - - RSU_LOCK(sc); - if (ic->ic_nrunning > 0) { - if (!sc->sc_running) { - rsu_init(sc); - startall = 1; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + rsu_init(ifp->if_softc); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rsu_stop(ifp, 1); } - } else if (sc->sc_running) - rsu_stop(sc); - RSU_UNLOCK(sc); + 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; + } - if (startall) - ieee80211_start_all(ic); + return (error); } /* @@ -2234,11 +2296,12 @@ rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct rsu_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rsu_softc *sc = ifp->if_softc; struct rsu_data *bf; /* prevent management frames from being sent if we're not ready */ - if (!sc->sc_running) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { m_freem(m); ieee80211_free_node(ni); return (ENETDOWN); @@ -2251,8 +2314,10 @@ rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, RSU_UNLOCK(sc); return (ENOBUFS); } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if (rsu_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); RSU_UNLOCK(sc); return (EIO); @@ -2263,17 +2328,23 @@ rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, } static void -rsu_init(struct rsu_softc *sc) +rsu_init(void *arg) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - uint8_t macaddr[IEEE80211_ADDR_LEN]; + struct rsu_softc *sc = arg; + + RSU_LOCK(sc); + rsu_init_locked(arg); + RSU_UNLOCK(sc); +} + +static void +rsu_init_locked(struct rsu_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; struct r92s_set_pwr_mode cmd; int error; int i; - RSU_ASSERT_LOCKED(sc); - /* Init host async commands ring. */ sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; @@ -2313,14 +2384,14 @@ rsu_init(struct rsu_softc *sc) rsu_read_1(sc, 0xfe5c) | 0x80); /* Set MAC address. */ - IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); - rsu_write_region_1(sc, R92S_MACID, macaddr, IEEE80211_ADDR_LEN); + rsu_write_region_1(sc, R92S_MACID, IF_LLADDR(ifp), + IEEE80211_ADDR_LEN); /* It really takes 1.5 seconds for the firmware to boot: */ usb_pause_mtx(&sc->sc_mtx, (3 * hz) / 2); - DPRINTF("setting MAC address to %s\n", ether_sprintf(macaddr)); - error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, macaddr, + DPRINTF("setting MAC address to %s\n", ether_sprintf(IF_LLADDR(ifp))); + error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, IF_LLADDR(ifp), IEEE80211_ADDR_LEN); if (error != 0) { device_printf(sc->sc_dev, "could not set MAC address\n"); @@ -2356,11 +2427,12 @@ rsu_init(struct rsu_softc *sc) /* Set default channel. */ ic->ic_bss->ni_chan = ic->ic_ibss_chan; #endif - sc->sc_scan_pass = 0; + sc->scan_pass = 0; usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]); /* We're ready to go. */ - sc->sc_running = 1; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; return; fail: /* Need to stop all failed transfers, if any */ @@ -2369,11 +2441,22 @@ fail: } static void -rsu_stop(struct rsu_softc *sc) +rsu_stop(struct ifnet *ifp, int disable) +{ + struct rsu_softc *sc = ifp->if_softc; + + RSU_LOCK(sc); + rsu_stop_locked(ifp, disable); + RSU_UNLOCK(sc); +} + +static void +rsu_stop_locked(struct ifnet *ifp, int disable __unused) { + struct rsu_softc *sc = ifp->if_softc; int i; - sc->sc_running = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); sc->sc_calibrating = 0; taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL); diff --git a/sys/dev/usb/wlan/if_rsureg.h b/sys/dev/usb/wlan/if_rsureg.h index 4e6cd88..db0751d 100644 --- a/sys/dev/usb/wlan/if_rsureg.h +++ b/sys/dev/usb/wlan/if_rsureg.h @@ -726,8 +726,7 @@ struct rsu_vap { #define RSU_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) struct rsu_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; int (*sc_newstate)(struct ieee80211com *, @@ -737,17 +736,17 @@ struct rsu_softc { const uint8_t *qid2idx; struct mtx sc_mtx; - u_int sc_running:1, - sc_calibrating:1, - sc_scan_pass:1; u_int cut; + int scan_pass; struct rsu_host_cmd_ring cmdq; struct rsu_data sc_rx[RSU_RX_LIST_COUNT]; struct rsu_data sc_tx[RSU_TX_LIST_COUNT]; struct rsu_data *fwcmd_data; uint8_t cmd_seq; uint8_t rom[128]; + uint8_t sc_bssid[IEEE80211_ADDR_LEN]; struct usb_xfer *sc_xfer[RSU_N_TRANSFER]; + uint8_t sc_calibrating; STAILQ_HEAD(, rsu_data) sc_rx_active; STAILQ_HEAD(, rsu_data) sc_rx_inactive; diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index 6a558f6..d5142ea 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -175,9 +175,8 @@ static int rum_tx_raw(struct rum_softc *, struct mbuf *, const struct ieee80211_bpf_params *); static int rum_tx_data(struct rum_softc *, struct mbuf *, struct ieee80211_node *); -static int rum_transmit(struct ieee80211com *, struct mbuf *); -static void rum_start(struct rum_softc *); -static void rum_parent(struct ieee80211com *); +static void rum_start(struct ifnet *); +static int rum_ioctl(struct ifnet *, u_long, caddr_t); static void rum_eeprom_read(struct rum_softc *, uint16_t, void *, int); static uint32_t rum_read(struct rum_softc *, uint16_t); @@ -199,7 +198,7 @@ static void rum_set_chan(struct rum_softc *, struct ieee80211_channel *); static void rum_enable_tsf_sync(struct rum_softc *); static void rum_enable_tsf(struct rum_softc *); -static void rum_update_slot(struct rum_softc *); +static void rum_update_slot(struct ifnet *); static void rum_set_bssid(struct rum_softc *, const uint8_t *); static void rum_set_macaddr(struct rum_softc *, const uint8_t *); static void rum_update_mcast(struct ieee80211com *); @@ -208,7 +207,8 @@ static void rum_setpromisc(struct rum_softc *); static const char *rum_get_rf(int); static void rum_read_eeprom(struct rum_softc *); static int rum_bbp_init(struct rum_softc *); -static void rum_init(struct rum_softc *); +static void rum_init_locked(struct rum_softc *); +static void rum_init(void *); static void rum_stop(struct rum_softc *); static void rum_load_microcode(struct rum_softc *, const uint8_t *, size_t); @@ -425,7 +425,8 @@ rum_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); struct rum_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; uint8_t iface_index, bands; uint32_t tmp; int error, ntries; @@ -436,7 +437,6 @@ rum_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); - mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = RT2573_IFACE_INDEX; error = usbd_transfer_setup(uaa->device, &iface_index, @@ -470,6 +470,24 @@ rum_attach(device_t self) rum_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); RUM_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, "rum", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rum_init; + ifp->if_ioctl = rum_ioctl; + ifp->if_start = rum_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 */ @@ -494,14 +512,13 @@ rum_attach(device_t self) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_bssid); ic->ic_update_promisc = rum_update_promisc; ic->ic_raw_xmit = rum_raw_xmit; ic->ic_scan_start = rum_scan_start; ic->ic_scan_end = rum_scan_end; ic->ic_set_channel = rum_set_channel; - ic->ic_transmit = rum_transmit; - ic->ic_parent = rum_parent; + ic->ic_vap_create = rum_vap_create; ic->ic_vap_delete = rum_vap_delete; ic->ic_update_mcast = rum_update_mcast; @@ -526,6 +543,8 @@ static int rum_detach(device_t self) { struct rum_softc *sc = device_get_softc(self); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; /* Prevent further ioctls */ RUM_LOCK(sc); @@ -540,9 +559,11 @@ rum_detach(device_t self) rum_unsetup_tx_list(sc); RUM_UNLOCK(sc); - if (sc->sc_ic.ic_softc == sc) - ieee80211_ifdetach(&sc->sc_ic); - mbufq_drain(&sc->sc_snd); + if (ifp) { + ic = ifp->if_l2com; + ieee80211_ifdetach(ic); + if_free(ifp); + } mtx_destroy(&sc->sc_mtx); return (0); } @@ -574,18 +595,21 @@ rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct rum_softc *sc = ic->ic_softc; + struct rum_softc *sc = ic->ic_ifp->if_softc; struct rum_vap *rvp; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - rvp = malloc(sizeof(struct rum_vap), M_80211_VAP, M_WAITOK | M_ZERO); + rvp = (struct rum_vap *) malloc(sizeof(struct rum_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return NULL; vap = &rvp->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(rvp, M_80211_VAP); return (NULL); @@ -600,8 +624,7 @@ rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -625,8 +648,13 @@ rum_tx_free(struct rum_tx_data *data, int txerr) struct rum_softc *sc = data->sc; if (data->m != NULL) { - ieee80211_tx_complete(data->ni, data->m, txerr); + if (data->m->m_flags & M_TXCB) + ieee80211_process_callback(data->ni, data->m, + txerr ? ETIMEDOUT : 0); + m_freem(data->m); data->m = NULL; + + ieee80211_free_node(data->ni); data->ni = NULL; } STAILQ_INSERT_TAIL(&sc->tx_free, data, next); @@ -683,7 +711,7 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct rum_vap *rvp = RUM_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct rum_softc *sc = ic->ic_softc; + struct rum_softc *sc = ic->ic_ifp->if_softc; const struct ieee80211_txparam *tp; enum ieee80211_state ostate; struct ieee80211_node *ni; @@ -717,12 +745,12 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_free_node(ni); return (-1); } - rum_update_slot(sc); + rum_update_slot(ic->ic_ifp); rum_enable_mrr(sc); rum_set_txpreamble(sc); rum_set_basicrates(sc); - IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid); - rum_set_bssid(sc, ic->ic_macaddr); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + rum_set_bssid(sc, sc->sc_bssid); } if (vap->iv_opmode == IEEE80211_M_HOSTAP || @@ -752,6 +780,7 @@ static void rum_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct rum_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap; struct rum_tx_data *data; struct mbuf *m; @@ -770,6 +799,9 @@ rum_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) rum_tx_free(data, 0); usbd_xfer_set_priv(xfer, NULL); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: @@ -812,14 +844,16 @@ tr_setup: usbd_transfer_submit(xfer); } - rum_start(sc); + RUM_UNLOCK(sc); + rum_start(ifp); + RUM_LOCK(sc); break; default: /* Error */ DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error)); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); data = usbd_xfer_get_priv(xfer); if (data != NULL) { rum_tx_free(data, error); @@ -846,7 +880,8 @@ static void rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct rum_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_node *ni; struct mbuf *m = NULL; struct usb_page_cache *pc; @@ -864,7 +899,7 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) if (len < (int)(RT2573_RX_DESC_SIZE + IEEE80211_MIN_LEN)) { DPRINTF("%s: xfer too short %d\n", device_get_nameunit(sc->sc_dev), len); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto tr_setup; } @@ -881,20 +916,21 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) * filled RUM_TXRX_CSR2: */ DPRINTFN(5, "PHY or CRC error\n"); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto tr_setup; } m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) { DPRINTF("could not allocate mbuf\n"); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto tr_setup; } usbd_copy_out(pc, RT2573_RX_DESC_SIZE, mtod(m, uint8_t *), len); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; if (ieee80211_radiotap_active(ic)) { @@ -932,8 +968,10 @@ tr_setup: (void) ieee80211_input_all(ic, m, rssi, RT2573_NOISE_FLOOR); } + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) + rum_start(ifp); RUM_LOCK(sc); - rum_start(sc); return; default: /* Error */ @@ -973,7 +1011,8 @@ static void rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, uint32_t flags, uint16_t xflags, int len, int rate) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t plcp_length; int remainder; @@ -1070,7 +1109,8 @@ static int rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_tx_data *data; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; @@ -1181,7 +1221,8 @@ static int rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_tx_data *data; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; @@ -1258,73 +1299,80 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) return 0; } -static int -rum_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct rum_softc *sc = ic->ic_softc; - int error; - - RUM_LOCK(sc); - if (!sc->sc_running) { - RUM_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RUM_UNLOCK(sc); - return (error); - } - rum_start(sc); - RUM_UNLOCK(sc); - - return (0); -} - static void -rum_start(struct rum_softc *sc) +rum_start(struct ifnet *ifp) { + struct rum_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; - RUM_LOCK_ASSERT(sc, MA_OWNED); - - if (!sc->sc_running) + RUM_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + RUM_UNLOCK(sc); return; - - while (sc->tx_nfree >= RUM_TX_MINFREE && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + } + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_nfree < RUM_TX_MINFREE) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; if (rum_tx_data(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } } + RUM_UNLOCK(sc); } -static void -rum_parent(struct ieee80211com *ic) +static int +rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct rum_softc *sc = ic->ic_softc; + struct rum_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error; int startall = 0; RUM_LOCK(sc); - if (sc->sc_detached) { + error = sc->sc_detached ? ENXIO : 0; + RUM_UNLOCK(sc); + if (error) + return (error); + + switch (cmd) { + case SIOCSIFFLAGS: + RUM_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + rum_init_locked(sc); + startall = 1; + } else + rum_setpromisc(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rum_stop(sc); + } RUM_UNLOCK(sc); - return; + 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; } - if (ic->ic_nrunning > 0) { - if (!sc->sc_running) { - rum_init(sc); - startall = 1; - } else - rum_setpromisc(sc); - } else if (sc->sc_running) - rum_stop(sc); - RUM_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + return error; } static void @@ -1524,7 +1572,8 @@ rum_select_antenna(struct rum_softc *sc) static void rum_enable_mrr(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = rum_read(sc, RT2573_TXRX_CSR4); @@ -1540,7 +1589,8 @@ rum_enable_mrr(struct rum_softc *sc) static void rum_set_txpreamble(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = rum_read(sc, RT2573_TXRX_CSR4); @@ -1555,7 +1605,8 @@ rum_set_txpreamble(struct rum_softc *sc) static void rum_set_basicrates(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; /* update basic rate set */ if (ic->ic_curmode == IEEE80211_MODE_11B) { @@ -1620,7 +1671,8 @@ rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) static void rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct rfprog *rfprog; uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT; int8_t power; @@ -1696,7 +1748,8 @@ rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) static void rum_enable_tsf_sync(struct rum_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); uint32_t tmp; @@ -1731,9 +1784,10 @@ rum_enable_tsf(struct rum_softc *sc) } static void -rum_update_slot(struct rum_softc *sc) +rum_update_slot(struct ifnet *ifp) { - struct ieee80211com *ic = &sc->sc_ic; + struct rum_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; uint8_t slottime; uint32_t tmp; @@ -1773,17 +1827,18 @@ rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) static void rum_setpromisc(struct rum_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; tmp = rum_read(sc, RT2573_TXRX_CSR0); tmp &= ~RT2573_DROP_NOT_TO_ME; - if (sc->sc_ic.ic_promisc == 0) + if (!(ifp->if_flags & IFF_PROMISC)) tmp |= RT2573_DROP_NOT_TO_ME; rum_write(sc, RT2573_TXRX_CSR0, tmp); - DPRINTF("%s promiscuous mode\n", sc->sc_ic.ic_promisc > 0 ? + DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); } @@ -1792,11 +1847,10 @@ rum_update_promisc(struct ieee80211com *ic) { struct rum_softc *sc = ic->ic_softc; - RUM_LOCK(sc); - if (!sc->sc_running) { - RUM_UNLOCK(sc); + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - } + + RUM_LOCK(sc); rum_setpromisc(sc); RUM_UNLOCK(sc); } @@ -1833,7 +1887,7 @@ rum_read_eeprom(struct rum_softc *sc) #endif /* read MAC address */ - rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, sc->sc_ic.ic_macaddr, 6); + rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, sc->sc_bssid, 6); rum_eeprom_read(sc, RT2573_EEPROM_ANTENNA, &val, 2); val = le16toh(val); @@ -1940,10 +1994,10 @@ rum_bbp_init(struct rum_softc *sc) } static void -rum_init(struct rum_softc *sc) +rum_init_locked(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; usb_error_t error; int i, ntries; @@ -1985,7 +2039,7 @@ rum_init(struct rum_softc *sc) /* clear STA registers */ rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); - rum_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + rum_set_macaddr(sc, IF_LLADDR(ifp)); /* initialize ASIC */ rum_write(sc, RT2573_MAC_CSR1, 4); @@ -2004,12 +2058,13 @@ rum_init(struct rum_softc *sc) RT2573_DROP_ACKCTS; if (ic->ic_opmode != IEEE80211_M_HOSTAP) tmp |= RT2573_DROP_TODS; - if (ic->ic_promisc == 0) + if (!(ifp->if_flags & IFF_PROMISC)) tmp |= RT2573_DROP_NOT_TO_ME; } rum_write(sc, RT2573_TXRX_CSR0, tmp); - sc->sc_running = 1; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; usbd_xfer_set_stall(sc->sc_xfer[RUM_BULK_WR]); usbd_transfer_start(sc->sc_xfer[RUM_BULK_RD]); return; @@ -2019,13 +2074,29 @@ fail: rum_stop(sc); } static void +rum_init(void *priv) +{ + struct rum_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RUM_LOCK(sc); + rum_init_locked(sc); + RUM_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void rum_stop(struct rum_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; RUM_LOCK_ASSERT(sc, MA_OWNED); - sc->sc_running = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); RUM_UNLOCK(sc); @@ -2117,23 +2188,27 @@ static int rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { - struct rum_softc *sc = ni->ni_ic->ic_softc; + struct ifnet *ifp = ni->ni_ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; RUM_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!sc->sc_running) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RUM_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return ENETDOWN; } if (sc->tx_nfree < RUM_TX_MINFREE) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; RUM_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return EIO; } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if (params == NULL) { /* * Legacy path; interpret frame contents to decide @@ -2153,6 +2228,7 @@ rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return 0; bad: + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); RUM_UNLOCK(sc); ieee80211_free_node(ni); return EIO; @@ -2186,7 +2262,8 @@ rum_ratectl_task(void *arg, int pending) struct rum_vap *rvp = arg; struct ieee80211vap *vap = &rvp->vap; struct ieee80211com *ic = vap->iv_ic; - struct rum_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; struct ieee80211_node *ni; int ok, fail; int sum, retrycnt; @@ -2206,8 +2283,7 @@ rum_ratectl_task(void *arg, int pending) (void) ieee80211_ratectl_rate(ni, NULL, 0); ieee80211_free_node(ni); - /* count TX retry-fail as Tx errors */ - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, fail); + if_inc_counter(ifp, IFCOUNTER_OERRORS, fail); /* count TX retry-fail as Tx errors */ usb_callout_reset(&rvp->ratectl_ch, hz, rum_ratectl_timeout, rvp); RUM_UNLOCK(sc); @@ -2216,14 +2292,15 @@ rum_ratectl_task(void *arg, int pending) static void rum_scan_start(struct ieee80211com *ic) { - struct rum_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; uint32_t tmp; RUM_LOCK(sc); /* abort TSF synchronization */ tmp = rum_read(sc, RT2573_TXRX_CSR9); rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); - rum_set_bssid(sc, ieee80211broadcastaddr); + rum_set_bssid(sc, ifp->if_broadcastaddr); RUM_UNLOCK(sc); } @@ -2231,11 +2308,11 @@ rum_scan_start(struct ieee80211com *ic) static void rum_scan_end(struct ieee80211com *ic) { - struct rum_softc *sc = ic->ic_softc; + struct rum_softc *sc = ic->ic_ifp->if_softc; RUM_LOCK(sc); rum_enable_tsf_sync(sc); - rum_set_bssid(sc, ic->ic_macaddr); + rum_set_bssid(sc, sc->sc_bssid); RUM_UNLOCK(sc); } @@ -2243,7 +2320,7 @@ rum_scan_end(struct ieee80211com *ic) static void rum_set_channel(struct ieee80211com *ic) { - struct rum_softc *sc = ic->ic_softc; + struct rum_softc *sc = ic->ic_ifp->if_softc; RUM_LOCK(sc); rum_set_chan(sc, ic->ic_curchan); @@ -2253,7 +2330,8 @@ rum_set_channel(struct ieee80211com *ic) static int rum_get_rssi(struct rum_softc *sc, uint8_t raw) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int lna, agc, rssi; lna = (raw >> 5) & 0x3; diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h index 35da6d3..17944aa 100644 --- a/sys/dev/usb/wlan/if_rumvar.h +++ b/sys/dev/usb/wlan/if_rumvar.h @@ -85,8 +85,7 @@ enum { }; struct rum_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; @@ -106,8 +105,8 @@ struct rum_softc { uint32_t sta[6]; uint32_t rf_regs[4]; uint8_t txpow[44]; - u_int sc_detached:1, - sc_running:1; + uint8_t sc_bssid[6]; + uint8_t sc_detached; struct { uint8_t val; diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index 193b9ad..ac14178 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -410,9 +410,8 @@ static int run_tx_param(struct run_softc *, struct mbuf *, const struct ieee80211_bpf_params *); static int run_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static int run_transmit(struct ieee80211com *, struct mbuf *); -static void run_start(struct run_softc *); -static void run_parent(struct ieee80211com *); +static void run_start(struct ifnet *); +static int run_ioctl(struct ifnet *, u_long, caddr_t); static void run_iq_calib(struct run_softc *, u_int); static void run_set_agc(struct run_softc *, uint8_t); static void run_select_chan_group(struct run_softc *, int); @@ -458,6 +457,7 @@ static void run_rt3593_rf_setup(struct run_softc *); static void run_rt5390_rf_setup(struct run_softc *); static int run_txrx_enable(struct run_softc *); static void run_adjust_freq_offset(struct run_softc *); +static void run_init(void *); static void run_init_locked(struct run_softc *); static void run_stop(void *); static void run_delay(struct run_softc *, u_int); @@ -702,7 +702,8 @@ run_attach(device_t self) { struct run_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; uint32_t ver; int ntries, error; uint8_t iface_index, bands; @@ -715,7 +716,6 @@ run_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, MTX_DEF); - mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = RT2860_IFACE_INDEX; @@ -754,10 +754,28 @@ run_attach(device_t self) device_printf(sc->sc_dev, "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), - sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr)); + sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid)); RUN_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, "run", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = run_init; + ifp->if_ioctl = run_ioctl; + ifp->if_start = run_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 */ @@ -794,7 +812,7 @@ run_attach(device_t self) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_bssid); ic->ic_scan_start = run_scan_start; ic->ic_scan_end = run_scan_end; @@ -806,10 +824,9 @@ run_attach(device_t self) ic->ic_wme.wme_update = run_wme_update; ic->ic_raw_xmit = run_raw_xmit; ic->ic_update_promisc = run_update_promisc; + ic->ic_vap_create = run_vap_create; ic->ic_vap_delete = run_vap_delete; - ic->ic_transmit = run_transmit; - ic->ic_parent = run_parent; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -835,7 +852,8 @@ static int run_detach(device_t self) { struct run_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; int i; RUN_LOCK(sc); @@ -854,15 +872,16 @@ run_detach(device_t self) run_unsetup_tx_list(sc, &sc->sc_epq[i]); RUN_UNLOCK(sc); - if (sc->sc_ic.ic_softc == sc) { + if (ifp) { + ic = ifp->if_l2com; /* drain tasks */ usb_callout_drain(&sc->ratectl_ch); ieee80211_draintask(ic, &sc->cmdq_task); ieee80211_draintask(ic, &sc->ratectl_task); ieee80211_ifdetach(ic); + if_free(ifp); } - mbufq_drain(&sc->sc_snd); mtx_destroy(&sc->sc_mtx); return (0); @@ -874,13 +893,14 @@ run_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct run_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct run_softc *sc = ifp->if_softc; struct run_vap *rvp; struct ieee80211vap *vap; int i; if (sc->rvp_cnt >= RUN_VAP_MAX) { - device_printf(sc->sc_dev, "number of VAPs maxed out\n"); + if_printf(ifp, "number of VAPs maxed out\n"); return (NULL); } @@ -906,21 +926,23 @@ run_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, break; } if (vap == NULL) { - device_printf(sc->sc_dev, - "wds only supported in ap mode\n"); + if_printf(ifp, "wds only supported in ap mode\n"); return (NULL); } break; default: - device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); + if_printf(ifp, "unknown opmode %d\n", opmode); return (NULL); } - rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO); + rvp = (struct run_vap *) malloc(sizeof(struct run_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return (NULL); vap = &rvp->vap; - if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, - bssid) != 0) { + if (ieee80211_vap_setup(ic, vap, name, unit, + opmode, flags, bssid, mac) != 0) { /* out of memory */ free(rvp, M_80211_VAP); return (NULL); @@ -947,8 +969,7 @@ run_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); /* complete setup */ - ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status, - mac); + ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); /* make sure id is always unique */ for (i = 0; i < RUN_VAP_MAX; i++) { @@ -974,6 +995,7 @@ static void run_vap_delete(struct ieee80211vap *vap) { struct run_vap *rvp = RUN_VAP(vap); + struct ifnet *ifp; struct ieee80211com *ic; struct run_softc *sc; uint8_t rvp_id; @@ -982,7 +1004,9 @@ run_vap_delete(struct ieee80211vap *vap) return; ic = vap->iv_ic; - sc = ic->ic_softc; + ifp = ic->ic_ifp; + + sc = ifp->if_softc; RUN_LOCK(sc); @@ -1716,7 +1740,6 @@ run_get_txpower(struct run_softc *sc) static int run_read_eeprom(struct run_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; int8_t delta_2ghz, delta_5ghz; uint32_t tmp; uint16_t val; @@ -1737,14 +1760,14 @@ run_read_eeprom(struct run_softc *sc) /* read MAC address */ run_srom_read(sc, RT2860_EEPROM_MAC01, &val); - ic->ic_macaddr[0] = val & 0xff; - ic->ic_macaddr[1] = val >> 8; + sc->sc_bssid[0] = val & 0xff; + sc->sc_bssid[1] = val >> 8; run_srom_read(sc, RT2860_EEPROM_MAC23, &val); - ic->ic_macaddr[2] = val & 0xff; - ic->ic_macaddr[3] = val >> 8; + sc->sc_bssid[2] = val & 0xff; + sc->sc_bssid[3] = val >> 8; run_srom_read(sc, RT2860_EEPROM_MAC45, &val); - ic->ic_macaddr[4] = val & 0xff; - ic->ic_macaddr[5] = val >> 8; + sc->sc_bssid[4] = val & 0xff; + sc->sc_bssid[5] = val >> 8; if (sc->mac_ver < 0x3593) { /* read vender BBP settings */ @@ -1979,7 +2002,7 @@ run_media_change(struct ifnet *ifp) struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_txparam *tp; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; uint8_t rate, ridx; int error; @@ -2010,7 +2033,7 @@ run_media_change(struct ifnet *ifp) #if 0 if ((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & RUN_RUNNING)){ + (ifp->if_drv_flags & IFF_DRV_RUNNING)){ run_init_locked(sc); } #endif @@ -2025,7 +2048,7 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { const struct ieee80211_txparam *tp; struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct run_vap *rvp = RUN_VAP(vap); enum ieee80211_state ostate; uint32_t sta[3]; @@ -2121,7 +2144,7 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) run_set_txpreamble(sc); run_set_basicrates(sc); ni = ieee80211_ref_node(vap->iv_bss); - IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); run_set_bssid(sc, ni->ni_bssid); ieee80211_free_node(ni); run_enable_tsf_sync(sc); @@ -2158,7 +2181,7 @@ static void run_wme_update_cb(void *arg) { struct ieee80211com *ic = arg; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_wme_state *wmesp = &ic->ic_wme; int aci, error = 0; @@ -2211,7 +2234,7 @@ err: static int run_wme_update(struct ieee80211com *ic) { - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; /* sometime called wothout lock */ if (mtx_owned(&ic->ic_comlock.mtx)) { @@ -2254,7 +2277,7 @@ run_key_set_cb(void *arg) struct ieee80211vap *vap = cmdq->arg1; struct ieee80211_key *k = cmdq->k; struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; uint32_t attr; uint16_t base, associd; @@ -2376,7 +2399,7 @@ run_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, const uint8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; uint32_t i; i = RUN_CMDQ_GET(&sc->cmdq_store); @@ -2444,7 +2467,7 @@ static int run_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) { struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_key *k0; uint32_t i; @@ -2475,7 +2498,7 @@ run_ratectl_to(void *arg) struct run_softc *sc = arg; /* do it in a process context, so it can go sleep */ - ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task); + ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); /* next timeout will be rescheduled in the callback task */ } @@ -2484,7 +2507,7 @@ static void run_ratectl_cb(void *arg, int pending) { struct run_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); if (vap == NULL) @@ -2517,6 +2540,7 @@ static void run_drain_fifo(void *arg) { struct run_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t stat; uint16_t (*wstat)[3]; uint8_t wcid, mcs, pid; @@ -2553,7 +2577,7 @@ run_drain_fifo(void *arg) if (stat & RT2860_TXQ_OK) (*wstat)[RUN_SUCCESS]++; else - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* * Check if there were retries, ie if the Tx success rate is * different from the requested rate. Note that it works only @@ -2576,6 +2600,8 @@ run_iter_func(void *arg, struct ieee80211_node *ni) { struct run_softc *sc = arg; struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; struct run_node *rn = (void *)ni; union run_stats sta[2]; uint16_t (*wstat)[3]; @@ -2597,8 +2623,7 @@ run_iter_func(void *arg, struct ieee80211_node *ni) goto fail; /* count failed TX as errors */ - if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, - le16toh(sta[0].error.fail)); + if_inc_counter(ifp, IFCOUNTER_OERRORS, le16toh(sta[0].error.fail)); retrycnt = le16toh(sta[1].tx.retry); success = le16toh(sta[1].tx.success); @@ -2636,7 +2661,7 @@ run_newassoc_cb(void *arg) { struct run_cmdq *cmdq = arg; struct ieee80211_node *ni = cmdq->arg1; - struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc; + struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; uint8_t wcid = cmdq->wcid; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2654,7 +2679,7 @@ run_newassoc(struct ieee80211_node *ni, int isnew) struct ieee80211_rateset *rs = &ni->ni_rates; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; uint8_t rate; uint8_t ridx; uint8_t wcid; @@ -2744,7 +2769,8 @@ run_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) static void run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) { - 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 rt2870_rxd *rxd; @@ -2763,7 +2789,7 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) rxwisize += sizeof(uint32_t); if (__predict_false(len > dmalen)) { m_freem(m); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF("bad RXWI length %u > %u\n", len, dmalen); return; } @@ -2773,7 +2799,7 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { m_freem(m); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); return; } @@ -2802,7 +2828,7 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) ieee80211_notify_michael_failure(ni->ni_vap, wh, rxwi->keyidx); m_freem(m); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF("MIC error. Someone is lying.\n"); return; } @@ -2811,6 +2837,7 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) rssi = rxwi->rssi[ant]; nf = run_rssi2dbm(sc, rssi, ant); + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; if (ni != NULL) { @@ -2863,7 +2890,7 @@ static void run_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct run_softc *sc = usbd_xfer_softc(xfer); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; struct mbuf *m = NULL; struct mbuf *m0; uint32_t dmalen; @@ -2901,7 +2928,7 @@ tr_setup: } if (sc->rx_m == NULL) { DPRINTF("could not allocate mbuf - idle with stall\n"); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); usbd_xfer_set_stall(xfer); usbd_xfer_set_frames(xfer, 0); } else { @@ -2921,9 +2948,12 @@ tr_setup: if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); + if (error == USB_ERR_TIMEOUT) device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(ic->ic_ierrors, 1); + + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + goto tr_setup; } if (sc->rx_m != NULL) { @@ -2971,7 +3001,7 @@ tr_setup: m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (__predict_false(m0 == NULL)) { DPRINTF("could not allocate mbuf\n"); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); break; } m_copydata(m, 4 /* skip 32-bit DMA-len header */, @@ -3018,7 +3048,8 @@ static void run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) { struct run_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 run_tx_data *data; struct ieee80211vap *vap = NULL; struct usb_page_cache *pc; @@ -3036,9 +3067,14 @@ run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) "bytes @ index %d\n", actlen, index); data = usbd_xfer_get_priv(xfer); + run_tx_free(pq, data, 0); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + usbd_xfer_set_priv(xfer, NULL); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: @@ -3055,7 +3091,11 @@ tr_setup: size + 3 + 8) > RUN_MAX_TXSZ) { DPRINTF("data overflow, %u bytes\n", m->m_pkthdr.len); + + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + run_tx_free(pq, data, 1); + goto tr_setup; } @@ -3092,8 +3132,12 @@ tr_setup: usbd_xfer_set_frame_len(xfer, 0, size); usbd_xfer_set_priv(xfer, data); + usbd_transfer_submit(xfer); - run_start(sc); + + RUN_UNLOCK(sc); + run_start(ifp); + RUN_LOCK(sc); break; @@ -3103,13 +3147,14 @@ tr_setup: data = usbd_xfer_get_priv(xfer); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + if (data != NULL) { if(data->ni != NULL) vap = data->ni->ni_vap; run_tx_free(pq, data, error); usbd_xfer_set_priv(xfer, NULL); } - if (vap == NULL) vap = TAILQ_FIRST(&ic->ic_vaps); @@ -3175,7 +3220,7 @@ static void run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) { struct mbuf *m = data->m; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = data->ni->ni_vap; struct ieee80211_frame *wh; struct rt2870_txd *txd; @@ -3238,7 +3283,7 @@ run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) static int run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; struct ieee80211_channel *chan; @@ -3406,7 +3451,8 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) static int run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct run_node *rn = (void *)ni; struct run_tx_data *data; struct ieee80211_frame *wh; @@ -3437,9 +3483,11 @@ run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) USETW(wh->i_dur, dur); } - if (sc->sc_epq[0].tx_nfree == 0) + if (sc->sc_epq[0].tx_nfree == 0) { /* let caller free mbuf */ + ifp->if_drv_flags |= IFF_DRV_OACTIVE; return (EIO); + } data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; @@ -3507,9 +3555,11 @@ run_sendprot(struct run_softc *sc, wflags = RT2860_TX_FRAG; /* check that there are free slots before allocating the mbuf */ - if (sc->sc_epq[0].tx_nfree == 0) + if (sc->sc_epq[0].tx_nfree == 0) { /* let caller free mbuf */ + sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; return (ENOBUFS); + } if (prot == IEEE80211_PROT_RTSCTS) { /* NB: CTS is the same size as an ACK */ @@ -3520,7 +3570,7 @@ run_sendprot(struct run_softc *sc, mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); } if (mprot == NULL) { - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); + if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); DPRINTF("could not allocate mbuf\n"); return (ENOBUFS); } @@ -3602,6 +3652,7 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, if (sc->sc_epq[0].tx_nfree == 0) { /* let caller free mbuf */ + sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; DPRINTF("sending raw frame, but tx ring is full\n"); return (EIO); } @@ -3640,31 +3691,36 @@ static int run_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { - struct run_softc *sc = ni->ni_ic->ic_softc; + struct ifnet *ifp = ni->ni_ic->ic_ifp; + struct run_softc *sc = ifp->if_softc; int error = 0; RUN_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & RUN_RUNNING)) { - error = ENETDOWN; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + error = ENETDOWN; goto done; } if (params == NULL) { /* tx mgt packet */ if ((error = run_tx_mgt(sc, m, ni)) != 0) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); DPRINTF("mgt tx failed\n"); goto done; } } else { /* tx raw packet with param */ if ((error = run_tx_param(sc, m, ni, params)) != 0) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); DPRINTF("tx with param failed\n"); goto done; } } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + done: RUN_UNLOCK(sc); @@ -3677,71 +3733,83 @@ done: return (error); } -static int -run_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct run_softc *sc = ic->ic_softc; - int error; - - RUN_LOCK(sc); - if ((sc->sc_flags & RUN_RUNNING) == 0) { - RUN_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RUN_UNLOCK(sc); - return (error); - } - run_start(sc); - RUN_UNLOCK(sc); - - return (0); -} - static void -run_start(struct run_softc *sc) +run_start(struct ifnet *ifp) { + struct run_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; - RUN_LOCK_ASSERT(sc, MA_OWNED); + RUN_LOCK(sc); - if ((sc->sc_flags & RUN_RUNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + RUN_UNLOCK(sc); return; + } + + for (;;) { + /* send data frames */ + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (run_tx(sc, m, ni) != 0) { - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } } + + RUN_UNLOCK(sc); } -static void -run_parent(struct ieee80211com *ic) +static int +run_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ifp->if_softc; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; int startall = 0; + int error; RUN_LOCK(sc); - if (sc->sc_detached) { + error = sc->sc_detached ? ENXIO : 0; + RUN_UNLOCK(sc); + if (error) + return (error); + + switch (cmd) { + case SIOCSIFFLAGS: + RUN_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ + startall = 1; + run_init_locked(sc); + } else + run_update_promisc_locked(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) { + run_stop(sc); + } + } RUN_UNLOCK(sc); - return; + 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; } - if (ic->ic_nrunning > 0) { - if (!(sc->sc_flags & RUN_RUNNING)) { - startall = 1; - run_init_locked(sc); - } else - run_update_promisc_locked(sc); - } else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1) - run_stop(sc); - RUN_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + return (error); } static void @@ -4728,7 +4796,7 @@ run_set_rx_antenna(struct run_softc *sc, int aux) static int run_set_chan(struct run_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; u_int chan, group; chan = ieee80211_chan2ieee(ic, c); @@ -4773,7 +4841,7 @@ run_set_chan(struct run_softc *sc, struct ieee80211_channel *c) static void run_set_channel(struct ieee80211com *ic) { - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; RUN_LOCK(sc); run_set_chan(sc, ic->ic_curchan); @@ -4785,7 +4853,7 @@ run_set_channel(struct ieee80211com *ic) static void run_scan_start(struct ieee80211com *ic) { - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; uint32_t tmp; RUN_LOCK(sc); @@ -4795,7 +4863,7 @@ run_scan_start(struct ieee80211com *ic) run_write(sc, RT2860_BCN_TIME_CFG, tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN)); - run_set_bssid(sc, ieee80211broadcastaddr); + run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr); RUN_UNLOCK(sc); @@ -4805,13 +4873,13 @@ run_scan_start(struct ieee80211com *ic) static void run_scan_end(struct ieee80211com *ic) { - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; RUN_LOCK(sc); run_enable_tsf_sync(sc); /* XXX keep local copy */ - run_set_bssid(sc, ic->ic_macaddr); + run_set_bssid(sc, sc->sc_bssid); RUN_UNLOCK(sc); @@ -4826,7 +4894,7 @@ static void run_update_beacon(struct ieee80211vap *vap, int item) { struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct run_vap *rvp = RUN_VAP(vap); int mcast = 0; uint32_t i; @@ -4871,7 +4939,7 @@ run_update_beacon_cb(void *arg) struct ieee80211vap *vap = arg; struct run_vap *rvp = RUN_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct rt2860_txwi txwi; struct mbuf *m; uint16_t txwisize; @@ -4919,7 +4987,7 @@ run_update_beacon_cb(void *arg) static void run_updateprot(struct ieee80211com *ic) { - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; uint32_t i; i = RUN_CMDQ_GET(&sc->cmdq_store); @@ -4933,7 +5001,7 @@ static void run_updateprot_cb(void *arg) { struct ieee80211com *ic = arg; - struct run_softc *sc = ic->ic_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; uint32_t tmp; tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; @@ -4957,7 +5025,7 @@ static void run_usb_timeout_cb(void *arg) { struct ieee80211vap *vap = arg; - struct run_softc *sc = vap->iv_ic->ic_softc; + struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -5003,12 +5071,12 @@ run_update_promisc_locked(struct run_softc *sc) run_read(sc, RT2860_RX_FILTR_CFG, &tmp); tmp |= RT2860_DROP_UC_NOME; - if (sc->sc_ic.ic_promisc > 0) + if (sc->sc_ifp->if_flags & IFF_PROMISC) tmp &= ~RT2860_DROP_UC_NOME; run_write(sc, RT2860_RX_FILTR_CFG, tmp); - DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ? + DPRINTF("%s promiscuous mode\n", (sc->sc_ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); } @@ -5017,7 +5085,7 @@ run_update_promisc(struct ieee80211com *ic) { struct run_softc *sc = ic->ic_softc; - if ((sc->sc_flags & RUN_RUNNING) == 0) + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; RUN_LOCK(sc); @@ -5028,7 +5096,7 @@ run_update_promisc(struct ieee80211com *ic) static void run_enable_tsf_sync(struct run_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; @@ -5093,7 +5161,7 @@ run_enable_mrr(struct run_softc *sc) static void run_set_txpreamble(struct run_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint32_t tmp; run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); @@ -5107,7 +5175,7 @@ run_set_txpreamble(struct run_softc *sc) static void run_set_basicrates(struct run_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* set basic rates mask */ if (ic->ic_curmode == IEEE80211_MODE_11B) @@ -5152,7 +5220,7 @@ run_updateslot(struct ieee80211com *ic) i = RUN_CMDQ_GET(&sc->cmdq_store); DPRINTF("cmdq_store=%d\n", i); sc->cmdq[i].func = run_updateslot_cb; - sc->cmdq[i].arg0 = ic; + sc->cmdq[i].arg0 = ic->ic_ifp; ieee80211_runtask(ic, &sc->cmdq_task); return; @@ -5162,8 +5230,9 @@ run_updateslot(struct ieee80211com *ic) static void run_updateslot_cb(void *arg) { - struct ieee80211com *ic = arg; - struct run_softc *sc = ic->ic_softc; + struct ifnet *ifp = arg; + struct run_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); @@ -5175,12 +5244,15 @@ run_updateslot_cb(void *arg) static void run_update_mcast(struct ieee80211com *ic) { + + /* h/w filter supports getting everything or nothing */ + ic->ic_ifp->if_flags |= IFF_ALLMULTI; } static int8_t run_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211_channel *c = ic->ic_curchan; int delta; @@ -5830,7 +5902,7 @@ run_rt5390_rf_setup(struct run_softc *sc) static int run_txrx_enable(struct run_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint32_t tmp; int error, ntries; @@ -5890,8 +5962,8 @@ run_adjust_freq_offset(struct run_softc *sc) static void run_init_locked(struct run_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; uint8_t bbp1, bbp3; int i; @@ -5921,7 +5993,7 @@ run_init_locked(struct run_softc *sc) for (i = 0; i != RUN_EP_QUEUES; i++) run_setup_tx_list(sc, &sc->sc_epq[i]); - run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + run_set_macaddr(sc, IF_LLADDR(ifp)); for (ntries = 0; ntries < 100; ntries++) { if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) @@ -6094,7 +6166,8 @@ run_init_locked(struct run_softc *sc) /* turn radio LED on */ run_set_leds(sc, RT2860_LED_RADIO); - sc->sc_flags |= RUN_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->cmdq_run = RUN_CMDQ_GO; for (i = 0; i != RUN_N_XFER; i++) @@ -6112,19 +6185,35 @@ fail: } static void +run_init(void *arg) +{ + struct run_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RUN_LOCK(sc); + run_init_locked(sc); + RUN_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); +} + +static void run_stop(void *arg) { struct run_softc *sc = (struct run_softc *)arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; int i; int ntries; RUN_LOCK_ASSERT(sc, MA_OWNED); - if (sc->sc_flags & RUN_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) run_set_leds(sc, 0); /* turn all LEDs off */ - sc->sc_flags &= ~RUN_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); sc->ratectl_run = RUN_RATECTL_OFF; sc->cmdq_run = sc->cmdq_key_set; diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h index b8cb12f..ad0fc30 100644 --- a/sys/dev/usb/wlan/if_runvar.h +++ b/sys/dev/usb/wlan/if_runvar.h @@ -151,16 +151,13 @@ struct run_endpoint_queue { }; struct run_softc { - struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mbufq sc_snd; device_t sc_dev; struct usb_device *sc_udev; + struct ifnet *sc_ifp; int sc_need_fwload; int sc_flags; #define RUN_FLAG_FWLOAD_NEEDED 0x01 -#define RUN_RUNNING 0x02 uint16_t wcid_stats[RT2870_WCID_MAX + 1][3]; #define RUN_TXCNT 0 @@ -206,6 +203,10 @@ struct run_softc { uint32_t txpow40mhz_2ghz[5]; uint32_t txpow40mhz_5ghz[5]; + uint8_t sc_bssid[6]; + + struct mtx sc_mtx; + struct run_endpoint_queue sc_epq[RUN_EP_QUEUES]; struct task ratectl_task; diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index 04e09204..fca9e39 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -279,11 +279,12 @@ static int uath_alloc_rx_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_tx_data_list(struct uath_softc *); -static int uath_init(struct uath_softc *); -static void uath_stop(struct uath_softc *); -static void uath_parent(struct ieee80211com *); -static int uath_transmit(struct ieee80211com *, struct mbuf *); -static void uath_start(struct uath_softc *); +static int uath_init_locked(void *); +static void uath_init(void *); +static void uath_stop_locked(struct ifnet *); +static void uath_stop(struct ifnet *); +static int uath_ioctl(struct ifnet *, u_long, caddr_t); +static void uath_start(struct ifnet *); static int uath_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void uath_scan_start(struct ieee80211com *); @@ -335,9 +336,11 @@ uath_attach(device_t dev) { struct uath_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; uint8_t bands, iface_index = UATH_IFACE_INDEX; /* XXX */ usb_error_t error; + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; sc->sc_udev = uaa->device; @@ -353,7 +356,6 @@ uath_attach(device_t dev) MTX_DEF); callout_init(&sc->stat_ch, 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, uath_usbconfig, UATH_N_XFERS, sc, &sc->sc_mtx); @@ -385,24 +387,31 @@ uath_attach(device_t dev) error = uath_host_available(sc); if (error != 0) { device_printf(sc->sc_dev, "could not initialize adapter\n"); - goto fail2; + goto fail3; } error = uath_get_devcap(sc); if (error != 0) { device_printf(sc->sc_dev, "could not get device capabilities\n"); - goto fail2; + goto fail3; } UATH_UNLOCK(sc); /* Create device sysctl node. */ 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); - error = uath_get_devstatus(sc, ic->ic_macaddr); + error = uath_get_devstatus(sc, macaddr); if (error != 0) { device_printf(sc->sc_dev, "could not get device status\n"); - goto fail2; + goto fail4; } /* @@ -411,15 +420,28 @@ uath_attach(device_t dev) error = uath_alloc_rx_data_list(sc); if (error != 0) { device_printf(sc->sc_dev, "could not allocate Rx data list\n"); - goto fail2; + goto fail4; } error = uath_alloc_tx_data_list(sc); if (error != 0) { device_printf(sc->sc_dev, "could not allocate Tx data list\n"); - goto fail2; + goto fail4; } 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_name = device_get_nameunit(dev); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -447,17 +469,16 @@ uath_attach(device_t dev) /* XXX turbo */ ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_raw_xmit = uath_raw_xmit; ic->ic_scan_start = uath_scan_start; ic->ic_scan_end = uath_scan_end; ic->ic_set_channel = uath_set_channel; + ic->ic_vap_create = uath_vap_create; ic->ic_vap_delete = uath_vap_delete; ic->ic_update_mcast = uath_update_mcast; ic->ic_update_promisc = uath_update_promisc; - ic->ic_transmit = uath_transmit; - ic->ic_parent = uath_parent; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -470,8 +491,9 @@ uath_attach(device_t dev) return (0); -fail2: UATH_UNLOCK(sc); - uath_free_cmd_list(sc, sc->sc_cmd); +fail4: if_free(ifp); +fail3: UATH_UNLOCK(sc); +fail2: uath_free_cmd_list(sc, sc->sc_cmd); fail1: usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); fail: return (error); @@ -481,7 +503,8 @@ static int uath_detach(device_t dev) { struct uath_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; /* @@ -502,10 +525,10 @@ uath_detach(device_t dev) STAILQ_INIT(&sc->sc_cmd_pending); STAILQ_INIT(&sc->sc_cmd_waiting); STAILQ_INIT(&sc->sc_cmd_inactive); - - uath_stop(sc); UATH_UNLOCK(sc); + uath_stop(ifp); + callout_drain(&sc->stat_ch); callout_drain(&sc->watchdog_ch); @@ -524,7 +547,7 @@ uath_detach(device_t dev) usbd_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + if_free(ifp); mtx_destroy(&sc->sc_mtx); return (0); } @@ -1044,12 +1067,15 @@ uath_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 uath_vap), M_80211_VAP, M_WAITOK | M_ZERO); + uvp = (struct uath_vap *) malloc(sizeof(struct uath_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); @@ -1061,7 +1087,7 @@ uath_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); } @@ -1076,17 +1102,18 @@ uath_vap_delete(struct ieee80211vap *vap) } static int -uath_init(struct uath_softc *sc) +uath_init_locked(void *arg) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct uath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t val; int error; UATH_ASSERT_LOCKED(sc); - if (sc->sc_flags & UATH_FLAG_INITDONE) - uath_stop(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + uath_stop_locked(ifp); /* reset variables */ sc->sc_intrx_nextnum = sc->sc_msgid = 0; @@ -1095,8 +1122,7 @@ uath_init(struct uath_softc *sc) uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof val, 0); /* set MAC address */ - uath_config_multi(sc, CFG_MAC_ADDR, - vap ? vap->iv_myaddr : ic->ic_macaddr, IEEE80211_ADDR_LEN); + uath_config_multi(sc, CFG_MAC_ADDR, IF_LLADDR(ifp), IEEE80211_ADDR_LEN); /* XXX honor net80211 state */ uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001); @@ -1145,6 +1171,8 @@ uath_init(struct uath_softc *sc) UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON, UATH_FILTER_OP_SET); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->sc_flags |= UATH_FLAG_INITDONE; callout_reset(&sc->watchdog_ch, hz, uath_watchdog, sc); @@ -1152,16 +1180,28 @@ uath_init(struct uath_softc *sc) return (0); fail: - uath_stop(sc); + uath_stop_locked(ifp); return (error); } static void -uath_stop(struct uath_softc *sc) +uath_init(void *arg) +{ + 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); + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); sc->sc_flags &= ~UATH_FLAG_INITDONE; callout_stop(&sc->stat_ch); @@ -1177,6 +1217,16 @@ uath_stop(struct uath_softc *sc) 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 uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val) { @@ -1279,13 +1329,13 @@ static void uath_watchdog(void *arg) { struct uath_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, "device timeout\n"); - /*uath_init(sc); XXX needs a process context! */ - counter_u64_add(ic->ic_oerrors, 1); + /*uath_init(ifp); XXX needs a process context! */ + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return; } callout_reset(&sc->watchdog_ch, hz, uath_watchdog, sc); @@ -1400,8 +1450,12 @@ uath_getbuf(struct uath_softc *sc) UATH_ASSERT_LOCKED(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__); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } return (bf); } @@ -1420,7 +1474,8 @@ static int uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c) { #ifdef UATH_DEBUG - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; #endif struct uath_cmd_reset reset; @@ -1499,28 +1554,47 @@ uath_wme_init(struct uath_softc *sc) return (error); } -static void -uath_parent(struct ieee80211com *ic) +static int +uath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct uath_softc *sc = ic->ic_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + struct uath_softc *sc = ifp->if_softc; + int error; int startall = 0; UATH_LOCK(sc); - if (sc->sc_flags & UATH_FLAG_INVALID) { - UATH_UNLOCK(sc); - return; - } + error = (sc->sc_flags & UATH_FLAG_INVALID) ? ENXIO : 0; + UATH_UNLOCK(sc); + if (error) + return (error); - if (ic->ic_nrunning > 0) { - if (!(sc->sc_flags & UATH_FLAG_INITDONE)) { - uath_init(sc); - startall = 1; + switch (cmd) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + uath_init(ifp->if_softc); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + uath_stop(ifp); } - } else if (sc->sc_flags & UATH_FLAG_INITDONE) - uath_stop(sc); - UATH_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + 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 @@ -1689,49 +1763,31 @@ uath_freetx(struct mbuf *m) } 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 -uath_start(struct uath_softc *sc) +uath_start(struct ifnet *ifp) { struct uath_data *bf; + struct uath_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m, *next; uath_datahead frags; - UATH_ASSERT_LOCKED(sc); - - if ((sc->sc_flags & UATH_FLAG_INITDONE) == 0 || + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || (sc->sc_flags & UATH_FLAG_INVALID)) return; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + UATH_LOCK(sc); + for (;;) { bf = uath_getbuf(sc); - if (bf == NULL) { - mbufq_prepend(&sc->sc_snd, m); + if (bf == NULL) 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; m->m_pkthdr.rcvif = NULL; @@ -1760,8 +1816,7 @@ uath_start(struct uath_softc *sc) next = m->m_nextpkt; if (uath_tx_start(sc, m, ni, bf) != 0) { bad: - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); reclaim: STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); UATH_STAT_INC(sc, st_tx_inactive); @@ -1792,6 +1847,7 @@ uath_start(struct uath_softc *sc) sc->sc_tx_timer = 5; } + UATH_UNLOCK(sc); } static int @@ -1799,19 +1855,19 @@ uath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; struct uath_data *bf; - struct uath_softc *sc = ic->ic_softc; + struct uath_softc *sc = ifp->if_softc; - UATH_LOCK(sc); /* prevent management frames from being sent if we're not ready */ if ((sc->sc_flags & UATH_FLAG_INVALID) || - !(sc->sc_flags & UATH_FLAG_INITDONE)) { + !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { m_freem(m); ieee80211_free_node(ni); - UATH_UNLOCK(sc); return (ENETDOWN); } + UATH_LOCK(sc); /* grab a TX buffer */ bf = uath_getbuf(sc); if (bf == NULL) { @@ -1824,6 +1880,7 @@ uath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, sc->sc_seqnum = 0; if (uath_tx_start(sc, m, ni, bf) != 0) { ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); UATH_STAT_INC(sc, st_tx_inactive); UATH_UNLOCK(sc); @@ -1850,11 +1907,12 @@ uath_scan_end(struct ieee80211com *ic) static void uath_set_channel(struct ieee80211com *ic) { - struct uath_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct uath_softc *sc = ifp->if_softc; UATH_LOCK(sc); if ((sc->sc_flags & UATH_FLAG_INVALID) || - (sc->sc_flags & UATH_FLAG_INITDONE) == 0) { + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { UATH_UNLOCK(sc); return; } @@ -1875,7 +1933,7 @@ uath_update_mcast(struct ieee80211com *ic) UATH_LOCK(sc); if ((sc->sc_flags & UATH_FLAG_INVALID) || - (sc->sc_flags & UATH_FLAG_INITDONE) == 0) { + (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { UATH_UNLOCK(sc); return; } @@ -1895,7 +1953,7 @@ uath_update_promisc(struct ieee80211com *ic) UATH_LOCK(sc); if ((sc->sc_flags & UATH_FLAG_INVALID) || - (sc->sc_flags & UATH_FLAG_INITDONE) == 0) { + (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { UATH_UNLOCK(sc); return; } @@ -1912,7 +1970,7 @@ static int uath_create_connection(struct uath_softc *sc, uint32_t connid) { const struct ieee80211_rateset *rs; - 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 uath_cmd_create_connection create; @@ -1963,7 +2021,7 @@ uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs) static int uath_write_associd(struct uath_softc *sc) { - 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 uath_cmd_set_associd associd; @@ -2017,7 +2075,7 @@ uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) int error; struct ieee80211_node *ni; struct ieee80211com *ic = vap->iv_ic; - struct uath_softc *sc = ic->ic_softc; + struct uath_softc *sc = ic->ic_ifp->if_softc; struct uath_vap *uvp = UATH_VAP(vap); DPRINTF(sc, UATH_DEBUG_STATE, @@ -2484,7 +2542,8 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, struct uath_rx_desc **pdesc) { struct uath_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 uath_chunk *chunk; struct uath_rx_desc *desc; struct mbuf *m = data->m, *mnew, *mp; @@ -2496,14 +2555,14 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, if (actlen < (int)UATH_MIN_RXBUFSZ) { DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, "%s: wrong xfer size (len=%d)\n", __func__, actlen); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } chunk = (struct uath_chunk *)data->buf; if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) { device_printf(sc->sc_dev, "%s: strange response\n", __func__); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); UATH_RESET_INTRX(sc); return (NULL); } @@ -2536,7 +2595,7 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, if ((sc->sc_intrx_len + sizeof(struct uath_rx_desc) + chunklen) > UATH_MAX_INTRX_SIZE) { UATH_STAT_INC(sc, st_invalidlen); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); if (sc->sc_intrx_head != NULL) m_freem(sc->sc_intrx_head); UATH_RESET_INTRX(sc); @@ -2561,7 +2620,7 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, if (mnew == NULL) { DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, "%s: can't get new mbuf, drop frame\n", __func__); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); if (sc->sc_intrx_head != NULL) m_freem(sc->sc_intrx_head); UATH_RESET_INTRX(sc); @@ -2602,7 +2661,7 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, "%s: bad descriptor (len=%d)\n", __func__, be32toh(desc->len)); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); UATH_STAT_INC(sc, st_toobigrxpkt); if (sc->sc_intrx_head != NULL) m_freem(sc->sc_intrx_head); @@ -2614,11 +2673,13 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, /* finalize mbuf */ if (sc->sc_intrx_head == NULL) { + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; m->m_data += sizeof(struct uath_chunk); } else { mp = sc->sc_intrx_head; + mp->m_pkthdr.rcvif = ifp; mp->m_flags |= M_PKTHDR; mp->m_pkthdr.len = sc->sc_intrx_len; m = mp; @@ -2644,6 +2705,7 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, tap->wr_antnoise = -95; } + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); UATH_RESET_INTRX(sc); return (m); @@ -2653,7 +2715,8 @@ static void uath_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct uath_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; @@ -2713,8 +2776,10 @@ setup: m = 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_start(sc); break; default: /* needs it to the inactive queue due to a error. */ @@ -2727,7 +2792,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; @@ -2738,22 +2803,40 @@ static void uath_data_txeof(struct usb_xfer *xfer, struct uath_data *data) { struct uath_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; UATH_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 && + (sc->sc_flags & UATH_FLAG_INVALID) == 0) { + /* XXX status? */ + ieee80211_process_callback(data->ni, m, 0); + } + m_freem(m); data->m = NULL; + } + if (data->ni) { + if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) + ieee80211_free_node(data->ni); data->ni = NULL; } sc->sc_tx_timer = 0; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static void uath_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) { struct uath_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct uath_data *data; UATH_ASSERT_LOCKED(sc); @@ -2785,18 +2868,19 @@ setup: usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); usbd_transfer_submit(xfer); - uath_start(sc); + UATH_UNLOCK(sc); + uath_start(ifp); + UATH_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); if ((sc->sc_flags & UATH_FLAG_INVALID) == 0) 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); diff --git a/sys/dev/usb/wlan/if_uathvar.h b/sys/dev/usb/wlan/if_uathvar.h index 56b5ba3..fae3604 100644 --- a/sys/dev/usb/wlan/if_uathvar.h +++ b/sys/dev/usb/wlan/if_uathvar.h @@ -183,8 +183,7 @@ struct uath_vap { #define UATH_VAP(vap) ((struct uath_vap *)(vap)) struct uath_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; void *sc_cmd_dma_buf; 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); diff --git a/sys/dev/usb/wlan/if_upgtvar.h b/sys/dev/usb/wlan/if_upgtvar.h index 3dcd335..c50276b 100644 --- a/sys/dev/usb/wlan/if_upgtvar.h +++ b/sys/dev/usb/wlan/if_upgtvar.h @@ -418,9 +418,8 @@ struct upgt_vap { #define UPGT_VAP(vap) ((struct upgt_vap *)(vap)) struct upgt_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; device_t sc_dev; + struct ifnet *sc_ifp; struct usb_device *sc_udev; void *sc_rx_dma_buf; void *sc_tx_dma_buf; @@ -430,8 +429,11 @@ struct upgt_softc { #define UPGT_FLAG_FWLOADED (1 << 0) #define UPGT_FLAG_INITDONE (1 << 1) #define UPGT_FLAG_DETACHED (1 << 2) + int sc_if_flags; int sc_debug; + uint8_t sc_myaddr[IEEE80211_ADDR_LEN]; + enum ieee80211_state sc_state; int sc_arg; int sc_led_blink; diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index e8224ba..79a5be0 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -149,9 +149,8 @@ static int ural_tx_mgt(struct ural_softc *, struct mbuf *, struct ieee80211_node *); static int ural_tx_data(struct ural_softc *, struct mbuf *, struct ieee80211_node *); -static int ural_transmit(struct ieee80211com *, struct mbuf *); -static void ural_start(struct ural_softc *); -static void ural_parent(struct ieee80211com *); +static void ural_start(struct ifnet *); +static int ural_ioctl(struct ifnet *, u_long, caddr_t); static void ural_set_testmode(struct ural_softc *); static void ural_eeprom_read(struct ural_softc *, uint16_t, void *, int); @@ -172,12 +171,12 @@ static void ural_set_chan(struct ural_softc *, static void ural_disable_rf_tune(struct ural_softc *); static void ural_enable_tsf_sync(struct ural_softc *); static void ural_enable_tsf(struct ural_softc *); -static void ural_update_slot(struct ural_softc *); +static void ural_update_slot(struct ifnet *); static void ural_set_txpreamble(struct ural_softc *); static void ural_set_basicrates(struct ural_softc *, const struct ieee80211_channel *); static void ural_set_bssid(struct ural_softc *, const uint8_t *); -static void ural_set_macaddr(struct ural_softc *, const uint8_t *); +static void ural_set_macaddr(struct ural_softc *, uint8_t *); static void ural_update_promisc(struct ieee80211com *); static void ural_setpromisc(struct ural_softc *); static const char *ural_get_rf(int); @@ -185,7 +184,8 @@ static void ural_read_eeprom(struct ural_softc *); static int ural_bbp_init(struct ural_softc *); static void ural_set_txantenna(struct ural_softc *, int); static void ural_set_rxantenna(struct ural_softc *, int); -static void ural_init(struct ural_softc *); +static void ural_init_locked(struct ural_softc *); +static void ural_init(void *); static void ural_stop(struct ural_softc *); static int ural_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); @@ -422,7 +422,8 @@ ural_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); struct ural_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; @@ -432,7 +433,6 @@ ural_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); - mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = RAL_IFACE_INDEX; error = usbd_transfer_setup(uaa->device, @@ -455,6 +455,24 @@ ural_attach(device_t self) device_printf(self, "MAC/BBP RT2570 (rev 0x%02x), RF %s\n", sc->asic_rev, ural_get_rf(sc->rf_rev)); + 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, "ural", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = ural_init; + ifp->if_ioctl = ural_ioctl; + ifp->if_start = ural_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 */ @@ -479,14 +497,13 @@ ural_attach(device_t self) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_bssid); ic->ic_update_promisc = ural_update_promisc; ic->ic_raw_xmit = ural_raw_xmit; ic->ic_scan_start = ural_scan_start; ic->ic_scan_end = ural_scan_end; ic->ic_set_channel = ural_set_channel; - ic->ic_parent = ural_parent; - ic->ic_transmit = ural_transmit; + ic->ic_vap_create = ural_vap_create; ic->ic_vap_delete = ural_vap_delete; @@ -510,7 +527,8 @@ static int ural_detach(device_t self) { struct ural_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; /* prevent further ioctls */ RAL_LOCK(sc); @@ -525,9 +543,11 @@ ural_detach(device_t self) ural_unsetup_tx_list(sc); RAL_UNLOCK(sc); - if (ic->ic_softc == sc) + if (ifp) { + ic = ifp->if_l2com; ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + if_free(ifp); + } mtx_destroy(&sc->sc_mtx); return (0); @@ -560,7 +580,7 @@ ural_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct ural_softc *sc = ic->ic_softc; + struct ural_softc *sc = ic->ic_ifp->if_softc; struct ural_vap *uvp; struct ieee80211vap *vap; @@ -574,7 +594,7 @@ ural_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); @@ -590,8 +610,7 @@ ural_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -615,8 +634,13 @@ ural_tx_free(struct ural_tx_data *data, int txerr) struct ural_softc *sc = data->sc; if (data->m != NULL) { - ieee80211_tx_complete(data->ni, data->m, txerr); + if (data->m->m_flags & M_TXCB) + ieee80211_process_callback(data->ni, data->m, + txerr ? ETIMEDOUT : 0); + m_freem(data->m); data->m = NULL; + + ieee80211_free_node(data->ni); data->ni = NULL; } STAILQ_INSERT_TAIL(&sc->tx_free, data, next); @@ -673,7 +697,7 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ural_vap *uvp = URAL_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct ural_softc *sc = ic->ic_softc; + struct ural_softc *sc = ic->ic_ifp->if_softc; const struct ieee80211_txparam *tp; struct ieee80211_node *ni; struct mbuf *m; @@ -707,11 +731,11 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_free_node(ni); return (-1); } - ural_update_slot(sc); + ural_update_slot(ic->ic_ifp); ural_set_txpreamble(sc); ural_set_basicrates(sc, ic->ic_bsschan); - IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid); - ural_set_bssid(sc, ic->ic_macaddr); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + ural_set_bssid(sc, sc->sc_bssid); } if (vap->iv_opmode == IEEE80211_M_HOSTAP || @@ -765,6 +789,7 @@ static void ural_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ural_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap; struct ural_tx_data *data; struct mbuf *m; @@ -782,6 +807,9 @@ ural_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) ural_tx_free(data, 0); usbd_xfer_set_priv(xfer, NULL); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: @@ -824,13 +852,16 @@ tr_setup: usbd_transfer_submit(xfer); } - ural_start(sc); + RAL_UNLOCK(sc); + ural_start(ifp); + RAL_LOCK(sc); break; default: /* Error */ DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error)); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); data = usbd_xfer_get_priv(xfer); if (data != NULL) { ural_tx_free(data, error); @@ -852,7 +883,8 @@ static void ural_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct ural_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_node *ni; struct mbuf *m = NULL; struct usb_page_cache *pc; @@ -870,7 +902,7 @@ ural_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) if (len < (int)(RAL_RX_DESC_SIZE + IEEE80211_MIN_LEN)) { DPRINTF("%s: xfer too short %d\n", device_get_nameunit(sc->sc_dev), len); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto tr_setup; } @@ -889,19 +921,20 @@ ural_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) * filled RAL_TXRX_CSR2: */ DPRINTFN(5, "PHY or CRC error\n"); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto tr_setup; } m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) { DPRINTF("could not allocate mbuf\n"); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); goto tr_setup; } usbd_copy_out(pc, 0, mtod(m, uint8_t *), len); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; if (ieee80211_radiotap_active(ic)) { @@ -940,8 +973,10 @@ tr_setup: } else (void) ieee80211_input_all(ic, m, rssi, nf); } + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) + ural_start(ifp); RAL_LOCK(sc); - ural_start(sc); return; default: /* Error */ @@ -981,7 +1016,8 @@ static void ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc, uint32_t flags, int len, int rate) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t plcp_length; int remainder; @@ -1030,10 +1066,12 @@ ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = sc->sc_ifp; const struct ieee80211_txparam *tp; struct ural_tx_data *data; if (sc->tx_nfree == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; m_freem(m0); ieee80211_free_node(ni); return (EIO); @@ -1310,73 +1348,78 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) return 0; } -static int -ural_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct ural_softc *sc = ic->ic_softc; - int error; - - RAL_LOCK(sc); - if (!sc->sc_running) { - RAL_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RAL_UNLOCK(sc); - return (error); - } - ural_start(sc); - RAL_UNLOCK(sc); - - return (0); -} - static void -ural_start(struct ural_softc *sc) +ural_start(struct ifnet *ifp) { + struct ural_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; - RAL_LOCK_ASSERT(sc, MA_OWNED); - - if (sc->sc_running == 0) + RAL_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + RAL_UNLOCK(sc); return; - - while (sc->tx_nfree >= RAL_TX_MINFREE && - (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + } + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_nfree < RAL_TX_MINFREE) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; if (ural_tx_data(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } } + RAL_UNLOCK(sc); } -static void -ural_parent(struct ieee80211com *ic) +static int +ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct ural_softc *sc = ic->ic_softc; + struct ural_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error; int startall = 0; RAL_LOCK(sc); - if (sc->sc_detached) { + error = sc->sc_detached ? ENXIO : 0; + RAL_UNLOCK(sc); + if (error) + return (error); + + switch (cmd) { + case SIOCSIFFLAGS: + RAL_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ural_init_locked(sc); + startall = 1; + } else + ural_setpromisc(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ural_stop(sc); + } RAL_UNLOCK(sc); - return; + if (startall) + ieee80211_start_all(ic); + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + default: + error = ether_ioctl(ifp, cmd, data); + break; } - if (ic->ic_nrunning > 0) { - if (sc->sc_running == 0) { - ural_init(sc); - startall = 1; - } else - ural_setpromisc(sc); - } else if (sc->sc_running) - ural_stop(sc); - RAL_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + return error; } static void @@ -1571,22 +1614,23 @@ ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val) static void ural_scan_start(struct ieee80211com *ic) { - struct ural_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ural_softc *sc = ifp->if_softc; RAL_LOCK(sc); ural_write(sc, RAL_TXRX_CSR19, 0); - ural_set_bssid(sc, ieee80211broadcastaddr); + ural_set_bssid(sc, ifp->if_broadcastaddr); RAL_UNLOCK(sc); } static void ural_scan_end(struct ieee80211com *ic) { - struct ural_softc *sc = ic->ic_softc; + struct ural_softc *sc = ic->ic_ifp->if_softc; RAL_LOCK(sc); ural_enable_tsf_sync(sc); - ural_set_bssid(sc, ic->ic_macaddr); + ural_set_bssid(sc, sc->sc_bssid); RAL_UNLOCK(sc); } @@ -1594,7 +1638,7 @@ ural_scan_end(struct ieee80211com *ic) static void ural_set_channel(struct ieee80211com *ic) { - struct ural_softc *sc = ic->ic_softc; + struct ural_softc *sc = ic->ic_ifp->if_softc; RAL_LOCK(sc); ural_set_chan(sc, ic->ic_curchan); @@ -1604,7 +1648,8 @@ ural_set_channel(struct ieee80211com *ic) static void ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint8_t power, tmp; int i, chan; @@ -1735,7 +1780,8 @@ ural_disable_rf_tune(struct ural_softc *sc) static void ural_enable_tsf_sync(struct ural_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); uint16_t logcwmin, preload, tmp; @@ -1771,9 +1817,10 @@ ural_enable_tsf(struct ural_softc *sc) #define RAL_RXTX_TURNAROUND 5 /* us */ static void -ural_update_slot(struct ural_softc *sc) +ural_update_slot(struct ifnet *ifp) { - struct ieee80211com *ic = &sc->sc_ic; + struct ural_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; uint16_t slottime, sifs, eifs; slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; @@ -1798,7 +1845,8 @@ ural_update_slot(struct ural_softc *sc) static void ural_set_txpreamble(struct ural_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t tmp; tmp = ural_read(sc, RAL_TXRX_CSR10); @@ -1845,7 +1893,7 @@ ural_set_bssid(struct ural_softc *sc, const uint8_t *bssid) } static void -ural_set_macaddr(struct ural_softc *sc, const uint8_t *addr) +ural_set_macaddr(struct ural_softc *sc, uint8_t *addr) { uint16_t tmp; @@ -1864,17 +1912,18 @@ ural_set_macaddr(struct ural_softc *sc, const uint8_t *addr) static void ural_setpromisc(struct ural_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; tmp = ural_read(sc, RAL_TXRX_CSR2); tmp &= ~RAL_DROP_NOT_TO_ME; - if (sc->sc_ic.ic_promisc == 0) + if (!(ifp->if_flags & IFF_PROMISC)) tmp |= RAL_DROP_NOT_TO_ME; ural_write(sc, RAL_TXRX_CSR2, tmp); - DPRINTF("%s promiscuous mode\n", sc->sc_ic.ic_promisc ? + DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); } @@ -1883,9 +1932,11 @@ ural_update_promisc(struct ieee80211com *ic) { struct ural_softc *sc = ic->ic_softc; + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + RAL_LOCK(sc); - if (sc->sc_running) - ural_setpromisc(sc); + ural_setpromisc(sc); RAL_UNLOCK(sc); } @@ -1907,7 +1958,6 @@ ural_get_rf(int rev) static void ural_read_eeprom(struct ural_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; uint16_t val; ural_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2); @@ -1920,7 +1970,7 @@ ural_read_eeprom(struct ural_softc *sc) sc->nb_ant = val & 0x3; /* read MAC address */ - ural_eeprom_read(sc, RAL_EEPROM_ADDRESS, ic->ic_macaddr, 6); + ural_eeprom_read(sc, RAL_EEPROM_ADDRESS, sc->sc_bssid, 6); /* read default values for BBP registers */ ural_eeprom_read(sc, RAL_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16); @@ -2014,11 +2064,11 @@ ural_set_rxantenna(struct ural_softc *sc, int antenna) } static void -ural_init(struct ural_softc *sc) +ural_init_locked(struct ural_softc *sc) { #define N(a) ((int)(sizeof (a) / sizeof ((a)[0]))) - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t tmp; int i, ntries; @@ -2065,7 +2115,7 @@ ural_init(struct ural_softc *sc) ural_set_txantenna(sc, sc->tx_ant); ural_set_rxantenna(sc, sc->rx_ant); - ural_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + ural_set_macaddr(sc, IF_LLADDR(ifp)); /* * Allocate Tx and Rx xfer queues. @@ -2078,12 +2128,13 @@ ural_init(struct ural_softc *sc) tmp |= RAL_DROP_CTL | RAL_DROP_BAD_VERSION; if (ic->ic_opmode != IEEE80211_M_HOSTAP) tmp |= RAL_DROP_TODS; - if (ic->ic_promisc == 0) + if (!(ifp->if_flags & IFF_PROMISC)) tmp |= RAL_DROP_NOT_TO_ME; } ural_write(sc, RAL_TXRX_CSR2, tmp); - sc->sc_running = 1; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; usbd_xfer_set_stall(sc->sc_xfer[URAL_BULK_WR]); usbd_transfer_start(sc->sc_xfer[URAL_BULK_RD]); return; @@ -2093,12 +2144,28 @@ fail: ural_stop(sc); } static void +ural_init(void *priv) +{ + struct ural_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RAL_LOCK(sc); + ural_init_locked(sc); + RAL_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void ural_stop(struct ural_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; RAL_LOCK_ASSERT(sc, MA_OWNED); - sc->sc_running = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* * Drain all the transfers, if not already drained: @@ -2126,23 +2193,27 @@ ural_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct ural_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ural_softc *sc = ifp->if_softc; RAL_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!sc->sc_running) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return ENETDOWN; } if (sc->tx_nfree < RAL_TX_MINFREE) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; RAL_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return EIO; } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if (params == NULL) { /* * Legacy path; interpret frame contents to decide @@ -2161,6 +2232,7 @@ ural_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, RAL_UNLOCK(sc); return 0; bad: + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); RAL_UNLOCK(sc); ieee80211_free_node(ni); return EIO; /* XXX */ @@ -2194,7 +2266,8 @@ ural_ratectl_task(void *arg, int pending) struct ural_vap *uvp = arg; struct ieee80211vap *vap = &uvp->vap; struct ieee80211com *ic = vap->iv_ic; - struct ural_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ural_softc *sc = ifp->if_softc; struct ieee80211_node *ni; int ok, fail; int sum, retrycnt; @@ -2213,8 +2286,7 @@ ural_ratectl_task(void *arg, int pending) ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt); (void) ieee80211_ratectl_rate(ni, NULL, 0); - /* count TX retry-fail as Tx errors */ - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, fail); + if_inc_counter(ifp, IFCOUNTER_OERRORS, fail); /* count TX retry-fail as Tx errors */ usb_callout_reset(&uvp->ratectl_ch, hz, ural_ratectl_timeout, uvp); RAL_UNLOCK(sc); diff --git a/sys/dev/usb/wlan/if_uralvar.h b/sys/dev/usb/wlan/if_uralvar.h index f40f71d..c62b0e4 100644 --- a/sys/dev/usb/wlan/if_uralvar.h +++ b/sys/dev/usb/wlan/if_uralvar.h @@ -89,8 +89,7 @@ enum { }; struct ural_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; @@ -110,8 +109,8 @@ struct ural_softc { uint16_t sta[11]; uint32_t rf_regs[4]; uint8_t txpow[14]; - u_int sc_detached:1, - sc_running:1; + uint8_t sc_bssid[6]; + uint8_t sc_detached; struct { uint8_t val; diff --git a/sys/dev/usb/wlan/if_urtw.c b/sys/dev/usb/wlan/if_urtw.c index f0d2674..f8b77d4 100644 --- a/sys/dev/usb/wlan/if_urtw.c +++ b/sys/dev/usb/wlan/if_urtw.c @@ -651,11 +651,11 @@ static struct ieee80211vap *urtw_vap_create(struct ieee80211com *, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void urtw_vap_delete(struct ieee80211vap *); -static void urtw_init(struct urtw_softc *); -static void urtw_stop(struct urtw_softc *); -static void urtw_parent(struct ieee80211com *); -static int urtw_transmit(struct ieee80211com *, struct mbuf *); -static void urtw_start(struct urtw_softc *); +static void urtw_init(void *); +static void urtw_stop(struct ifnet *); +static void urtw_stop_locked(struct ifnet *); +static int urtw_ioctl(struct ifnet *, u_long, caddr_t); +static void urtw_start(struct ifnet *); static int urtw_alloc_rx_data_list(struct urtw_softc *); static int urtw_alloc_tx_data_list(struct urtw_softc *); static int urtw_raw_xmit(struct ieee80211_node *, struct mbuf *, @@ -784,7 +784,8 @@ urtw_attach(device_t dev) int ret = ENXIO; struct urtw_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; uint8_t bands, iface_index = URTW_IFACE_INDEX; /* XXX */ uint16_t n_setup; uint32_t data; @@ -806,7 +807,6 @@ urtw_attach(device_t dev) TASK_INIT(&sc->sc_led_task, 0, urtw_ledtask, sc); TASK_INIT(&sc->sc_updateslot_task, 0, urtw_updateslottask, sc); callout_init(&sc->sc_watchdog_ch, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); if (sc->sc_flags & URTW_RTL8187B) { setup_start = urtw_8187b_usbconfig; @@ -861,6 +861,26 @@ urtw_attach(device_t dev) sc->sc_currate = 3; sc->sc_preamble_mode = urtw_preamble_mode; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not allocate ifnet\n"); + ret = ENOMEM; + goto fail1; + } + + ifp->if_softc = sc; + if_initname(ifp, "urtw", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = urtw_init; + ifp->if_ioctl = urtw_ioctl; + ifp->if_start = urtw_start; + /* XXX URTW_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_name = device_get_nameunit(dev); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -881,7 +901,7 @@ urtw_attach(device_t dev) setbit(&bands, IEEE80211_MODE_11G); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_bssid); ic->ic_raw_xmit = urtw_raw_xmit; ic->ic_scan_start = urtw_scan_start; ic->ic_scan_end = urtw_scan_end; @@ -890,8 +910,6 @@ urtw_attach(device_t dev) ic->ic_vap_create = urtw_vap_create; ic->ic_vap_delete = urtw_vap_delete; ic->ic_update_mcast = urtw_update_mcast; - ic->ic_parent = urtw_parent; - ic->ic_transmit = urtw_transmit; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -905,9 +923,8 @@ urtw_attach(device_t dev) ieee80211_announce(ic); return (0); -fail: - URTW_UNLOCK(sc); - usbd_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ? +fail: URTW_UNLOCK(sc); +fail1: usbd_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ? URTW_8187B_N_XFERS : URTW_8187L_N_XFERS); fail0: return (ret); @@ -917,16 +934,18 @@ static int urtw_detach(device_t dev) { struct urtw_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; unsigned int n_xfers; /* Prevent further ioctls */ URTW_LOCK(sc); sc->sc_flags |= URTW_DETACHED; - urtw_stop(sc); URTW_UNLOCK(sc); + urtw_stop(ifp); + ieee80211_draintask(ic, &sc->sc_updateslot_task); ieee80211_draintask(ic, &sc->sc_led_task); @@ -960,7 +979,7 @@ urtw_detach(device_t dev) usbd_transfer_unsetup(sc->sc_xfer, n_xfers); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + if_free(ifp); mtx_destroy(&sc->sc_mtx); return (0); } @@ -1013,12 +1032,15 @@ urtw_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 urtw_vap), M_80211_VAP, M_WAITOK | M_ZERO); + uvp = (struct urtw_vap *) malloc(sizeof(struct urtw_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); @@ -1030,7 +1052,7 @@ urtw_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); } @@ -1045,15 +1067,15 @@ urtw_vap_delete(struct ieee80211vap *vap) } static void -urtw_init(struct urtw_softc *sc) +urtw_init_locked(void *arg) { - usb_error_t error; int ret; + struct urtw_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + usb_error_t error; - URTW_ASSERT_LOCKED(sc); - - if (sc->sc_flags & URTW_RUNNING) - urtw_stop(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + urtw_stop_locked(ifp); error = (sc->sc_flags & URTW_RTL8187B) ? urtw_adapter_start_b(sc) : urtw_adapter_start(sc); @@ -1083,13 +1105,24 @@ urtw_init(struct urtw_softc *sc) if (sc->sc_flags & URTW_RTL8187B) usbd_transfer_start(sc->sc_xfer[URTW_8187B_BULK_TX_STATUS]); - sc->sc_flags |= URTW_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc); fail: return; } +static void +urtw_init(void *arg) +{ + struct urtw_softc *sc = arg; + + URTW_LOCK(sc); + urtw_init_locked(arg); + URTW_UNLOCK(sc); +} + static usb_error_t urtw_adapter_start_b(struct urtw_softc *sc) { @@ -1182,7 +1215,6 @@ fail: static usb_error_t urtw_adapter_start(struct urtw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; usb_error_t error; error = urtw_reset(sc); @@ -1202,8 +1234,8 @@ urtw_adapter_start(struct urtw_softc *sc) if (error) goto fail; /* applying MAC address again. */ - urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)ic->ic_macaddr)[0]); - urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)ic->ic_macaddr)[1] & 0xffff); + urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]); + urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff); error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); if (error) goto fail; @@ -1306,14 +1338,13 @@ urtw_do_request(struct urtw_softc *sc, } static void -urtw_stop(struct urtw_softc *sc) +urtw_stop_locked(struct ifnet *ifp) { + struct urtw_softc *sc = ifp->if_softc; uint8_t data8; usb_error_t error; - URTW_ASSERT_LOCKED(sc); - - sc->sc_flags &= ~URTW_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); error = urtw_intr_disable(sc); if (error) @@ -1346,6 +1377,16 @@ fail: } static void +urtw_stop(struct ifnet *ifp) +{ + struct urtw_softc *sc = ifp->if_softc; + + URTW_LOCK(sc); + urtw_stop_locked(ifp); + URTW_UNLOCK(sc); +} + +static void urtw_abort_xfers(struct urtw_softc *sc) { int i, max; @@ -1360,71 +1401,72 @@ urtw_abort_xfers(struct urtw_softc *sc) usbd_transfer_stop(sc->sc_xfer[i]); } -static void -urtw_parent(struct ieee80211com *ic) +static int +urtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct urtw_softc *sc = ic->ic_softc; + struct urtw_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error; int startall = 0; URTW_LOCK(sc); - if (sc->sc_flags & URTW_DETACHED) { - URTW_UNLOCK(sc); - return; - } + error = (sc->sc_flags & URTW_DETACHED) ? ENXIO : 0; + URTW_UNLOCK(sc); + if (error) + return (error); - if (ic->ic_nrunning > 0) { - if (sc->sc_flags & URTW_RUNNING) { - if (ic->ic_promisc > 0 || ic->ic_allmulti > 0) - urtw_set_multi(sc); + 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)) + urtw_set_multi(sc); + } else { + urtw_init(ifp->if_softc); + startall = 1; + } } else { - urtw_init(sc); - startall = 1; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + urtw_stop(ifp); } - } else if (sc->sc_flags & URTW_RUNNING) - urtw_stop(sc); - URTW_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); -} - -static int -urtw_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct urtw_softc *sc = ic->ic_softc; - int error; - - URTW_LOCK(sc); - if ((sc->sc_flags & URTW_RUNNING) == 0) { - URTW_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - URTW_UNLOCK(sc); - return (error); + 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; } - urtw_start(sc); - URTW_UNLOCK(sc); - - return (0); + return (error); } static void -urtw_start(struct urtw_softc *sc) +urtw_start(struct ifnet *ifp) { struct urtw_data *bf; + struct urtw_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; - URTW_ASSERT_LOCKED(sc); - - if ((sc->sc_flags & URTW_RUNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + URTW_LOCK(sc); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; bf = urtw_getbuf(sc); if (bf == NULL) { - mbufq_prepend(&sc->sc_snd, m); + IFQ_DRV_PREPEND(&ifp->if_snd, m); break; } @@ -1432,8 +1474,7 @@ urtw_start(struct urtw_softc *sc) m->m_pkthdr.rcvif = NULL; if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_NORMAL) != 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; @@ -1442,6 +1483,7 @@ urtw_start(struct urtw_softc *sc) sc->sc_txtimer = 5; callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc); } + URTW_UNLOCK(sc); } static int @@ -1523,11 +1565,12 @@ urtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct urtw_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; struct urtw_data *bf; + struct urtw_softc *sc = ifp->if_softc; /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & URTW_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { m_freem(m); ieee80211_free_node(ni); return ENETDOWN; @@ -1541,8 +1584,10 @@ urtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return (ENOBUFS); /* XXX */ } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_LOW) != 0) { ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); URTW_UNLOCK(sc); return (EIO); @@ -1570,7 +1615,8 @@ urtw_scan_end(struct ieee80211com *ic) static void urtw_set_channel(struct ieee80211com *ic) { - struct urtw_softc *sc = ic->ic_softc; + struct urtw_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = sc->sc_ifp; uint32_t data, orig; usb_error_t error; @@ -1580,7 +1626,7 @@ urtw_set_channel(struct ieee80211com *ic) * initialization would be failed if setting a channel is called before * the init have done. */ - if (!(sc->sc_flags & URTW_RUNNING)) + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) return; if (sc->sc_curchan != NULL && sc->sc_curchan == ic->ic_curchan) @@ -1627,10 +1673,11 @@ static int urtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, struct urtw_data *data, int prior) { + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); struct ieee80211_key *k; const struct ieee80211_txparam *tp; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct usb_xfer *rtl8187b_pipes[URTW_8187B_TXPIPE_MAX] = { sc->sc_xfer[URTW_8187B_BULK_TX_BE], @@ -1815,7 +1862,7 @@ static int urtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; - struct urtw_softc *sc = ic->ic_softc; + struct urtw_softc *sc = ic->ic_ifp->if_softc; struct urtw_vap *uvp = URTW_VAP(vap); struct ieee80211_node *ni; usb_error_t error = 0; @@ -1868,11 +1915,12 @@ static void urtw_watchdog(void *arg) { struct urtw_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, urtw_watchdog, sc); @@ -1882,7 +1930,17 @@ urtw_watchdog(void *arg) static void urtw_set_multi(void *arg) { - /* XXX don't know how to set a device. Lack of docs. */ + struct urtw_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + + if (!(ifp->if_flags & IFF_UP)) + return; + + /* + * 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 usb_error_t @@ -1944,7 +2002,8 @@ urtw_rtl2rate(uint32_t rate) static usb_error_t urtw_update_msr(struct urtw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint8_t data; usb_error_t error; @@ -2085,25 +2144,24 @@ urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data) static usb_error_t urtw_get_macaddr(struct urtw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; uint32_t data; usb_error_t error; error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data); if (error != 0) goto fail; - ic->ic_macaddr[0] = data & 0xff; - ic->ic_macaddr[1] = (data & 0xff00) >> 8; + sc->sc_bssid[0] = data & 0xff; + sc->sc_bssid[1] = (data & 0xff00) >> 8; error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data); if (error != 0) goto fail; - ic->ic_macaddr[2] = data & 0xff; - ic->ic_macaddr[3] = (data & 0xff00) >> 8; + sc->sc_bssid[2] = data & 0xff; + sc->sc_bssid[3] = (data & 0xff00) >> 8; error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data); if (error != 0) goto fail; - ic->ic_macaddr[4] = data & 0xff; - ic->ic_macaddr[5] = (data & 0xff00) >> 8; + sc->sc_bssid[4] = data & 0xff; + sc->sc_bssid[5] = (data & 0xff00) >> 8; fail: return (error); } @@ -3175,7 +3233,7 @@ fail: static usb_error_t urtw_8225v2b_rf_init(struct urtw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; +#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int i; uint8_t data8; usb_error_t error; @@ -3223,8 +3281,8 @@ urtw_8225v2b_rf_init(struct urtw_softc *sc) urtw_write8_m(sc, URTW_CONFIG1, data8); /* applying MAC address again. */ - urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)ic->ic_macaddr)[0]); - urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)ic->ic_macaddr)[1] & 0xffff); + urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]); + urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff); error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); if (error) @@ -3235,7 +3293,7 @@ urtw_8225v2b_rf_init(struct urtw_softc *sc) /* * MAC configuration */ - for (i = 0; i < nitems(urtw_8225v2b_rf_part1); i++) + for (i = 0; i < N(urtw_8225v2b_rf_part1); i++) urtw_write8_m(sc, urtw_8225v2b_rf_part1[i].reg, urtw_8225v2b_rf_part1[i].val); urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50); @@ -3268,7 +3326,7 @@ urtw_8225v2b_rf_init(struct urtw_softc *sc) urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff); usb_pause_mtx(&sc->sc_mtx, 1100); - for (i = 0; i < nitems(urtw_8225v2b_rf_part0); i++) { + for (i = 0; i < N(urtw_8225v2b_rf_part0); i++) { urtw_8225_write(sc, urtw_8225v2b_rf_part0[i].reg, urtw_8225v2b_rf_part0[i].val); usb_pause_mtx(&sc->sc_mtx, 1); @@ -3314,7 +3372,7 @@ urtw_8225v2b_rf_init(struct urtw_softc *sc) } urtw_8187_write_phy_ofdm(sc, 0x80, 0x10); - for (i = 0; i < nitems(urtw_8225v2b_rf_part2); i++) + for (i = 0; i < N(urtw_8225v2b_rf_part2); i++) urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2b_rf_part2[i].val); urtw_write32_m(sc, URTW_8187B_AC_VO, (7 << 12) | (3 << 8) | 0x1c); @@ -3729,7 +3787,8 @@ static void urtw_led_ch(void *arg) { struct urtw_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; ieee80211_runtask(ic, &sc->sc_led_task); } @@ -3876,7 +3935,8 @@ fail: static usb_error_t urtw_rx_setconf(struct urtw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t data; usb_error_t error; @@ -3901,7 +3961,7 @@ urtw_rx_setconf(struct urtw_softc *sc) data = data | URTW_RX_FILTER_CRCERR; if (ic->ic_opmode == IEEE80211_M_MONITOR || - ic->ic_promisc > 0 || ic->ic_allmulti > 0) { + (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { data = data | URTW_RX_FILTER_ALLMAC; } else { data = data | URTW_RX_FILTER_NICMAC; @@ -3928,13 +3988,14 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p, struct ieee80211_frame *wh; struct mbuf *m, *mnew; struct urtw_softc *sc = data->sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint8_t noise = 0, rate; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); if (actlen < (int)URTW_MIN_RXBUFSZ) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } @@ -3945,7 +4006,7 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p, (actlen - (sizeof(struct urtw_8187b_rxhdr)))); flen = le32toh(rx->flag) & 0xfff; if (flen > actlen) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf; @@ -3959,7 +4020,7 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p, (actlen - (sizeof(struct urtw_8187l_rxhdr)))); flen = le32toh(rx->flag) & 0xfff; if (flen > actlen) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } @@ -3971,7 +4032,7 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p, mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (mnew == NULL) { - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return (NULL); } @@ -3980,6 +4041,7 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p, data->buf = mtod(mnew, uint8_t *); /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = flen - IEEE80211_CRC_LEN; if (ieee80211_radiotap_active(ic)) { @@ -4005,7 +4067,8 @@ static void urtw_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct urtw_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; @@ -4066,7 +4129,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; @@ -4080,7 +4143,7 @@ static void urtw_txstatus_eof(struct usb_xfer *xfer) { struct urtw_softc *sc = usbd_xfer_softc(xfer); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; int actlen, type, pktretry, seq; uint64_t val; @@ -4095,7 +4158,7 @@ urtw_txstatus_eof(struct usb_xfer *xfer) pktretry = val & 0xff; seq = (val >> 16) & 0xff; if (pktretry == URTW_TX_MAXRETRY) - counter_u64_add(ic->ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); DPRINTF(sc, URTW_DEBUG_TXSTATUS, "pktretry %d seq %#x\n", pktretry, seq); } @@ -4105,7 +4168,7 @@ static void urtw_bulk_tx_status_callback(struct usb_xfer *xfer, usb_error_t error) { struct urtw_softc *sc = usbd_xfer_softc(xfer); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; void *dma_buf = usbd_xfer_get_frame_buffer(xfer, 0); URTW_ASSERT_LOCKED(sc); @@ -4123,7 +4186,7 @@ setup: default: 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; @@ -4134,22 +4197,38 @@ static void urtw_txeof(struct usb_xfer *xfer, struct urtw_data *data) { struct urtw_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; URTW_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; } sc->sc_txtimer = 0; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static void urtw_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) { struct urtw_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct urtw_data *data; URTW_ASSERT_LOCKED(sc); @@ -4177,17 +4256,18 @@ setup: usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); usbd_transfer_submit(xfer); - urtw_start(sc); + URTW_UNLOCK(sc); + urtw_start(ifp); + URTW_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); @@ -4221,8 +4301,12 @@ urtw_getbuf(struct urtw_softc *sc) URTW_ASSERT_LOCKED(sc); bf = _urtw_getbuf(sc); - if (bf == NULL) + if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; + DPRINTF(sc, URTW_DEBUG_XMIT, "%s: stop queue\n", __func__); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } return (bf); } @@ -4294,14 +4378,14 @@ static void urtw_updateslottask(void *arg, int pending) { struct urtw_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int error; - URTW_LOCK(sc); - if ((sc->sc_flags & URTW_RUNNING) == 0) { - URTW_UNLOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - } + + URTW_LOCK(sc); if (sc->sc_flags & URTW_RTL8187B) { urtw_write8_m(sc, URTW_SIFS, 0x22); if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) 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); diff --git a/sys/dev/usb/wlan/if_urtwnreg.h b/sys/dev/usb/wlan/if_urtwnreg.h index 0ca9db7..2bbec7a 100644 --- a/sys/dev/usb/wlan/if_urtwnreg.h +++ b/sys/dev/usb/wlan/if_urtwnreg.h @@ -1172,8 +1172,7 @@ enum { #define URTWN_EP_QUEUES URTWN_BULK_RX struct urtwn_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; @@ -1181,7 +1180,6 @@ struct urtwn_softc { u_int sc_flags; #define URTWN_FLAG_CCK_HIPWR 0x01 #define URTWN_DETACHED 0x02 -#define URTWN_RUNNING 0x04 u_int chip; #define URTWN_CHIP_92C 0x01 @@ -1226,6 +1224,7 @@ struct urtwn_softc { uint8_t ht40_tx_pwr[5]; int8_t bw20_tx_pwr_diff; int8_t ofdm_tx_pwr_diff; + uint8_t sc_bssid[IEEE80211_ADDR_LEN]; struct callout sc_watchdog_ch; struct mtx sc_mtx; diff --git a/sys/dev/usb/wlan/if_urtwvar.h b/sys/dev/usb/wlan/if_urtwvar.h index a423214..e99cbf4 100644 --- a/sys/dev/usb/wlan/if_urtwvar.h +++ b/sys/dev/usb/wlan/if_urtwvar.h @@ -93,14 +93,14 @@ struct urtw_vap { #define URTW_VAP(vap) ((struct urtw_vap *)(vap)) struct urtw_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; struct mtx sc_mtx; void *sc_tx_dma_buf; int sc_debug; + int sc_if_flags; int sc_flags; #define URTW_INIT_ONCE (1 << 1) #define URTW_RTL8187B (1 << 2) @@ -108,13 +108,13 @@ struct urtw_softc { #define URTW_RTL8187B_REV_D (1 << 4) #define URTW_RTL8187B_REV_E (1 << 5) #define URTW_DETACHED (1 << 6) -#define URTW_RUNNING (1 << 7) enum ieee80211_state sc_state; int sc_epromtype; #define URTW_EEPROM_93C46 0 #define URTW_EEPROM_93C56 1 uint8_t sc_crcmon; + uint8_t sc_bssid[IEEE80211_ADDR_LEN]; struct ieee80211_channel *sc_curchan; diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index a86ab8a..8f9035e 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -154,12 +154,12 @@ static int zyd_set_beacon_interval(struct zyd_softc *, int); static void zyd_rx_data(struct usb_xfer *, int, uint16_t); static int zyd_tx_start(struct zyd_softc *, struct mbuf *, struct ieee80211_node *); -static int zyd_transmit(struct ieee80211com *, struct mbuf *); -static void zyd_start(struct zyd_softc *); +static void zyd_start(struct ifnet *); static int zyd_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void zyd_parent(struct ieee80211com *); +static int zyd_ioctl(struct ifnet *, u_long, caddr_t); static void zyd_init_locked(struct zyd_softc *); +static void zyd_init(void *); static void zyd_stop(struct zyd_softc *); static int zyd_loadfirmware(struct zyd_softc *); static void zyd_scan_start(struct ieee80211com *); @@ -333,7 +333,8 @@ zyd_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct zyd_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; uint8_t iface_index, bands; int error; @@ -352,7 +353,6 @@ zyd_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, MTX_DEF); STAILQ_INIT(&sc->sc_rqh); - mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = ZYD_IFACE_INDEX; error = usbd_transfer_setup(uaa->device, @@ -372,6 +372,22 @@ zyd_attach(device_t dev) } ZYD_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; + } + ifp->if_softc = sc; + if_initname(ifp, "zyd", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = zyd_init; + ifp->if_ioctl = zyd_ioctl; + ifp->if_start = zyd_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 */ @@ -392,17 +408,16 @@ zyd_attach(device_t dev) setbit(&bands, IEEE80211_MODE_11G); ieee80211_init_channels(ic, NULL, &bands); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, sc->sc_bssid); ic->ic_raw_xmit = zyd_raw_xmit; ic->ic_scan_start = zyd_scan_start; ic->ic_scan_end = zyd_scan_end; ic->ic_set_channel = zyd_set_channel; + ic->ic_vap_create = zyd_vap_create; ic->ic_vap_delete = zyd_vap_delete; ic->ic_update_mcast = zyd_update_mcast; ic->ic_update_promisc = zyd_update_mcast; - ic->ic_parent = zyd_parent; - ic->ic_transmit = zyd_transmit; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), @@ -424,7 +439,8 @@ static int zyd_detach(device_t dev) { struct zyd_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; unsigned int x; /* @@ -449,9 +465,11 @@ zyd_detach(device_t dev) /* free USB transfers and some data buffers */ usbd_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); - if (ic->ic_softc == sc) + if (ifp) { + ic = ifp->if_l2com; ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); + if_free(ifp); + } mtx_destroy(&sc->sc_mtx); return (0); @@ -468,12 +486,15 @@ zyd_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return (NULL); - zvp = malloc(sizeof(struct zyd_vap), M_80211_VAP, M_WAITOK | M_ZERO); + zvp = (struct zyd_vap *) malloc(sizeof(struct zyd_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (zvp == NULL) + return (NULL); vap = &zvp->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(zvp, M_80211_VAP); return (NULL); @@ -488,7 +509,7 @@ zyd_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); } @@ -509,8 +530,13 @@ zyd_tx_free(struct zyd_tx_data *data, int txerr) struct zyd_softc *sc = data->sc; if (data->m != NULL) { - ieee80211_tx_complete(data->ni, data->m, txerr); + if (data->m->m_flags & M_TXCB) + ieee80211_process_callback(data->ni, data->m, + txerr ? ETIMEDOUT : 0); + m_freem(data->m); data->m = NULL; + + ieee80211_free_node(data->ni); data->ni = NULL; } STAILQ_INSERT_TAIL(&sc->tx_free, data, next); @@ -567,7 +593,7 @@ zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct zyd_vap *zvp = ZYD_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct zyd_softc *sc = ic->ic_softc; + struct zyd_softc *sc = ic->ic_ifp->if_softc; int error; DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, @@ -592,8 +618,8 @@ zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) /* make data LED blink upon Tx */ zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); - IEEE80211_ADDR_COPY(ic->ic_macaddr, vap->iv_bss->ni_bssid); - zyd_set_bssid(sc, ic->ic_macaddr); + IEEE80211_ADDR_COPY(sc->sc_bssid, vap->iv_bss->ni_bssid); + zyd_set_bssid(sc, sc->sc_bssid); break; default: break; @@ -611,7 +637,8 @@ static void zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct zyd_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 ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni; struct zyd_cmd *cmd = &sc->sc_ibuf; @@ -654,9 +681,7 @@ zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) ieee80211_free_node(ni); } if (le16toh(retry->count) & 0x100) - /* too many retries */ - if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, - 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* too many retries */ break; } case ZYD_NOTIF_IORD: @@ -1218,7 +1243,8 @@ zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) #define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int error = 0, i; struct zyd_softc *sc = rf->rf_sc; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6; int chan = ieee80211_chan2ieee(ic, c); @@ -1906,7 +1932,7 @@ zyd_get_macaddr(struct zyd_softc *sc) USETW(req.wIndex, 0); USETW(req.wLength, IEEE80211_ADDR_LEN); - error = zyd_do_request(sc, &req, sc->sc_ic.ic_macaddr); + error = zyd_do_request(sc, &req, sc->sc_bssid); if (error != 0) { device_printf(sc->sc_dev, "could not read EEPROM: %s\n", usbd_errstr(error)); @@ -1978,41 +2004,36 @@ fail: static void zyd_set_multi(struct zyd_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - uint32_t low, high; int error; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ifmultiaddr *ifma; + uint32_t low, high; + uint8_t v; - if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; low = 0x00000000; high = 0x80000000; - if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_allmulti > 0 || - ic->ic_promisc > 0) { + if (ic->ic_opmode == IEEE80211_M_MONITOR || + (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { low = 0xffffffff; high = 0xffffffff; } else { - struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint8_t v; - - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - v = ((uint8_t *)LLADDR((struct sockaddr_dl *) - ifma->ifma_addr))[5] >> 2; - if (v < 32) - low |= 1 << v; - else - high |= 1 << (v - 32); - } - if_maddr_runlock(ifp); + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + v = ((uint8_t *)LLADDR((struct sockaddr_dl *) + ifma->ifma_addr))[5] >> 2; + if (v < 32) + low |= 1 << v; + else + high |= 1 << (v - 32); } + if_maddr_runlock(ifp); } /* reprogram multicast global hash table */ @@ -2029,6 +2050,9 @@ zyd_update_mcast(struct ieee80211com *ic) { struct zyd_softc *sc = ic->ic_softc; + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + ZYD_LOCK(sc); zyd_set_multi(sc); ZYD_UNLOCK(sc); @@ -2037,7 +2061,8 @@ zyd_update_mcast(struct ieee80211com *ic) static int zyd_set_rxfilter(struct zyd_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t rxfilter; switch (ic->ic_opmode) { @@ -2062,7 +2087,8 @@ static void zyd_set_chan(struct zyd_softc *sc, struct ieee80211_channel *c) { int error; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct zyd_rf *rf = &sc->sc_rf; uint32_t tmp; int chan; @@ -2153,7 +2179,8 @@ static void zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) { struct zyd_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 zyd_plcphdr plcp; struct zyd_rx_stat stat; struct usb_page_cache *pc; @@ -2163,7 +2190,7 @@ zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) if (len < ZYD_MIN_FRAGSZ) { DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too short (length=%d)\n", device_get_nameunit(sc->sc_dev), len); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } pc = usbd_xfer_get_frame(xfer, 0); @@ -2174,7 +2201,7 @@ zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) DPRINTF(sc, ZYD_DEBUG_RECV, "%s: RX status indicated error (%x)\n", device_get_nameunit(sc->sc_dev), stat.flags); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } @@ -2186,7 +2213,7 @@ zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) if (rlen > (int)MCLBYTES) { DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too long (length=%d)\n", device_get_nameunit(sc->sc_dev), rlen); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } else if (rlen > (int)MHLEN) m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); @@ -2195,9 +2222,10 @@ zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) if (m == NULL) { DPRINTF(sc, ZYD_DEBUG_RECV, "%s: could not allocate rx mbuf\n", device_get_nameunit(sc->sc_dev)); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = rlen; usbd_copy_out(pc, offset + sizeof(plcp), mtod(m, uint8_t *), rlen); @@ -2227,7 +2255,8 @@ static void zyd_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct zyd_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_node *ni; struct zyd_rx_desc desc; struct mbuf *m; @@ -2299,8 +2328,10 @@ tr_setup: } else (void)ieee80211_input_all(ic, m, rssi, nf); } + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) + zyd_start(ifp); ZYD_LOCK(sc); - zyd_start(sc); break; default: /* Error */ @@ -2355,6 +2386,7 @@ static void zyd_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct zyd_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap; struct zyd_tx_data *data; struct mbuf *m; @@ -2373,6 +2405,9 @@ zyd_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) zyd_tx_free(data, 0); usbd_xfer_set_priv(xfer, NULL); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: @@ -2405,14 +2440,16 @@ tr_setup: usbd_xfer_set_priv(xfer, data); usbd_transfer_submit(xfer); } - zyd_start(sc); + ZYD_UNLOCK(sc); + zyd_start(ifp); + ZYD_LOCK(sc); break; default: /* Error */ DPRINTF(sc, ZYD_DEBUG_ANY, "transfer error, %s\n", usbd_errstr(error)); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); data = usbd_xfer_get_priv(xfer); usbd_xfer_set_priv(xfer, NULL); if (data != NULL) @@ -2553,45 +2590,31 @@ zyd_tx_start(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) return (0); } -static int -zyd_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct zyd_softc *sc = ic->ic_softc; - int error; - - ZYD_LOCK(sc); - if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) { - ZYD_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - ZYD_UNLOCK(sc); - return (error); - } - zyd_start(sc); - ZYD_UNLOCK(sc); - - return (0); -} - static void -zyd_start(struct zyd_softc *sc) +zyd_start(struct ifnet *ifp) { + struct zyd_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; - ZYD_LOCK_ASSERT(sc, MA_OWNED); - - while (sc->tx_nfree > 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ZYD_LOCK(sc); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_nfree == 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (zyd_tx_start(sc, m, ni) != 0) { ieee80211_free_node(ni); - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); break; } } + ZYD_UNLOCK(sc); } static int @@ -2599,17 +2622,19 @@ zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct zyd_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct zyd_softc *sc = ifp->if_softc; ZYD_LOCK(sc); /* prevent management frames from being sent if we're not ready */ - if (!(sc->sc_flags & ZYD_FLAG_RUNNING)) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { ZYD_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); return (ENETDOWN); } if (sc->tx_nfree == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; ZYD_UNLOCK(sc); m_freem(m); ieee80211_free_node(ni); @@ -2623,6 +2648,7 @@ zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, */ if (zyd_tx_start(sc, m, ni) != 0) { ZYD_UNLOCK(sc); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); return (EIO); } @@ -2630,35 +2656,56 @@ zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return (0); } -static void -zyd_parent(struct ieee80211com *ic) +static int +zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct zyd_softc *sc = ic->ic_softc; + struct zyd_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error; int startall = 0; ZYD_LOCK(sc); - if (sc->sc_flags & ZYD_FLAG_DETACHED) { + error = (sc->sc_flags & ZYD_FLAG_DETACHED) ? ENXIO : 0; + ZYD_UNLOCK(sc); + if (error) + return (error); + + switch (cmd) { + case SIOCSIFFLAGS: + ZYD_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + zyd_init_locked(sc); + startall = 1; + } else + zyd_set_multi(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + zyd_stop(sc); + } ZYD_UNLOCK(sc); - return; + 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; } - if (ic->ic_nrunning > 0) { - if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) { - zyd_init_locked(sc); - startall = 1; - } else - zyd_set_multi(sc); - } else if (sc->sc_flags & ZYD_FLAG_RUNNING) - zyd_stop(sc); - ZYD_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + return (error); } static void zyd_init_locked(struct zyd_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct usb_config_descriptor *cd; int error; uint32_t val; @@ -2710,12 +2757,12 @@ zyd_init_locked(struct zyd_softc *sc) sc->sc_flags |= ZYD_FLAG_INITONCE; } - if (sc->sc_flags & ZYD_FLAG_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) zyd_stop(sc); DPRINTF(sc, ZYD_DEBUG_INIT, "setting MAC address to %6D\n", - vap ? vap->iv_myaddr : ic->ic_macaddr, ":"); - error = zyd_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + IF_LLADDR(ifp), ":"); + error = zyd_set_macaddr(sc, IF_LLADDR(ifp)); if (error != 0) return; @@ -2751,7 +2798,8 @@ zyd_init_locked(struct zyd_softc *sc) /* enable interrupts */ zyd_write32_m(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); - sc->sc_flags |= ZYD_FLAG_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; usbd_xfer_set_stall(sc->sc_xfer[ZYD_BULK_WR]); usbd_transfer_start(sc->sc_xfer[ZYD_BULK_RD]); usbd_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); @@ -2763,13 +2811,29 @@ fail: zyd_stop(sc); } static void +zyd_init(void *priv) +{ + struct zyd_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + ZYD_LOCK(sc); + zyd_init_locked(sc); + ZYD_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void zyd_stop(struct zyd_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int error; ZYD_LOCK_ASSERT(sc, MA_OWNED); - sc->sc_flags &= ~ZYD_FLAG_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* * Drain all the transfers, if not already drained: @@ -2861,29 +2925,30 @@ zyd_loadfirmware(struct zyd_softc *sc) static void zyd_scan_start(struct ieee80211com *ic) { - struct zyd_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct zyd_softc *sc = ifp->if_softc; ZYD_LOCK(sc); /* want broadcast address while scanning */ - zyd_set_bssid(sc, ieee80211broadcastaddr); + zyd_set_bssid(sc, ifp->if_broadcastaddr); ZYD_UNLOCK(sc); } static void zyd_scan_end(struct ieee80211com *ic) { - struct zyd_softc *sc = ic->ic_softc; + struct zyd_softc *sc = ic->ic_ifp->if_softc; ZYD_LOCK(sc); /* restore previous bssid */ - zyd_set_bssid(sc, ic->ic_macaddr); + zyd_set_bssid(sc, sc->sc_bssid); ZYD_UNLOCK(sc); } static void zyd_set_channel(struct ieee80211com *ic) { - struct zyd_softc *sc = ic->ic_softc; + struct zyd_softc *sc = ic->ic_ifp->if_softc; ZYD_LOCK(sc); zyd_set_chan(sc, ic->ic_curchan); diff --git a/sys/dev/usb/wlan/if_zydreg.h b/sys/dev/usb/wlan/if_zydreg.h index ec61d06..05d94e3 100644 --- a/sys/dev/usb/wlan/if_zydreg.h +++ b/sys/dev/usb/wlan/if_zydreg.h @@ -1249,8 +1249,7 @@ enum { }; struct zyd_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct usb_device *sc_udev; @@ -1261,13 +1260,13 @@ struct zyd_softc { #define ZYD_FLAG_INITONCE (1 << 1) #define ZYD_FLAG_INITDONE (1 << 2) #define ZYD_FLAG_DETACHED (1 << 3) -#define ZYD_FLAG_RUNNING (1 << 4) struct zyd_rf sc_rf; STAILQ_HEAD(, zyd_rq) sc_rtx; STAILQ_HEAD(, zyd_rq) sc_rqh; + uint8_t sc_bssid[IEEE80211_ADDR_LEN]; uint16_t sc_fwbase; uint8_t sc_regdomain; uint8_t sc_macrev; diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index f8af231..b316d46 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -116,9 +116,11 @@ static struct ieee80211vap *wi_vap_create(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void wi_vap_delete(struct ieee80211vap *vap); -static int wi_transmit(struct ieee80211com *, struct mbuf *); -static void wi_start(struct wi_softc *); -static int wi_start_tx(struct wi_softc *, struct wi_frame *, struct mbuf *); +static void wi_stop_locked(struct wi_softc *sc, int disable); +static void wi_start_locked(struct ifnet *); +static void wi_start(struct ifnet *); +static int wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr, + struct mbuf *m0); static int wi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static int wi_newstate_sta(struct ieee80211vap *, enum ieee80211_state, int); @@ -129,8 +131,10 @@ static void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf); static int wi_reset(struct wi_softc *); static void wi_watchdog(void *); -static void wi_parent(struct ieee80211com *); +static int wi_ioctl(struct ifnet *, u_long, caddr_t); static void wi_media_status(struct ifnet *, struct ifmediareq *); +static uint64_t wi_get_counter(struct ifnet *, ift_counter); + static void wi_rx_intr(struct wi_softc *); static void wi_tx_intr(struct wi_softc *); static void wi_tx_ex_intr(struct wi_softc *); @@ -149,10 +153,10 @@ static int wi_write_ssid(struct wi_softc *, int, u_int8_t *, int); static int wi_cmd(struct wi_softc *, int, int, int, int); static int wi_seek_bap(struct wi_softc *, int, int); static int wi_read_bap(struct wi_softc *, int, int, void *, int); -static int wi_write_bap(struct wi_softc *, int, int, const void *, int); +static int wi_write_bap(struct wi_softc *, int, int, void *, int); static int wi_mwrite_bap(struct wi_softc *, int, int, struct mbuf *, int); static int wi_read_rid(struct wi_softc *, int, void *, int *); -static int wi_write_rid(struct wi_softc *, int, const void *, int); +static int wi_write_rid(struct wi_softc *, int, void *, int); static int wi_write_appie(struct wi_softc *, int, const struct ieee80211_appie *); static void wi_scan_start(struct ieee80211com *); @@ -233,7 +237,8 @@ int wi_attach(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; + struct ifnet *ifp; int i, nrates, buflen; u_int16_t val; u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE]; @@ -244,6 +249,15 @@ wi_attach(device_t dev) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int error; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc\n"); + wi_free(dev); + return ENOSPC; + } + ic = ifp->if_l2com; sc->sc_firmware_type = WI_NOTYPE; sc->wi_cmd_count = 500; @@ -295,7 +309,6 @@ wi_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); /* * Read the station address. @@ -304,13 +317,12 @@ wi_attach(device_t dev) * the probe to fail. */ buflen = IEEE80211_ADDR_LEN; - error = wi_read_rid(sc, WI_RID_MAC_NODE, &ic->ic_macaddr, &buflen); + error = wi_read_rid(sc, WI_RID_MAC_NODE, macaddr, &buflen); if (error != 0) { buflen = IEEE80211_ADDR_LEN; - error = wi_read_rid(sc, WI_RID_MAC_NODE, &ic->ic_macaddr, - &buflen); + error = wi_read_rid(sc, WI_RID_MAC_NODE, macaddr, &buflen); } - if (error || IEEE80211_ADDR_EQ(&ic->ic_macaddr, empty_macaddr)) { + if (error || IEEE80211_ADDR_EQ(macaddr, empty_macaddr)) { if (error != 0) device_printf(dev, "mac read failed %d\n", error); else { @@ -321,6 +333,18 @@ wi_attach(device_t dev) return (error); } + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = wi_ioctl; + ifp->if_start = wi_start; + ifp->if_init = wi_init; + ifp->if_get_counter = wi_get_counter; + 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(dev); ic->ic_phytype = IEEE80211_T_DS; @@ -434,17 +458,16 @@ wi_attach(device_t dev) sc->sc_portnum = WI_DEFAULT_PORT; - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); ic->ic_raw_xmit = wi_raw_xmit; ic->ic_scan_start = wi_scan_start; ic->ic_scan_end = wi_scan_end; ic->ic_set_channel = wi_set_channel; + ic->ic_vap_create = wi_vap_create; ic->ic_vap_delete = wi_vap_delete; ic->ic_update_mcast = wi_update_mcast; ic->ic_update_promisc = wi_update_promisc; - ic->ic_transmit = wi_transmit; - ic->ic_parent = wi_parent; ieee80211_radiotap_attach(ic, &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), @@ -460,6 +483,7 @@ wi_attach(device_t dev) if (error) { device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); ieee80211_ifdetach(ic); + if_free(sc->sc_ifp); wi_free(dev); return error; } @@ -471,20 +495,21 @@ int wi_detach(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; WI_LOCK(sc); /* check if device was removed */ sc->wi_gone |= !bus_child_present(dev); - wi_stop(sc, 0); + wi_stop_locked(sc, 0); WI_UNLOCK(sc); ieee80211_ifdetach(ic); bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); + if_free(sc->sc_ifp); wi_free(dev); - mbufq_drain(&sc->sc_snd); mtx_destroy(&sc->sc_mtx); return (0); } @@ -495,16 +520,19 @@ wi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct wi_softc *sc = ic->ic_softc; + struct wi_softc *sc = ic->ic_ifp->if_softc; struct wi_vap *wvp; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - wvp = malloc(sizeof(struct wi_vap), M_80211_VAP, M_WAITOK | M_ZERO); + wvp = (struct wi_vap *) malloc(sizeof(struct wi_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (wvp == NULL) + return NULL; vap = &wvp->wv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); vap->iv_max_aid = WI_MAX_AID; @@ -538,7 +566,7 @@ wi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, } /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, wi_media_status, mac); + ieee80211_vap_attach(vap, ieee80211_media_change, wi_media_status); ic->ic_opmode = opmode; return vap; } @@ -557,9 +585,7 @@ wi_shutdown(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - WI_LOCK(sc); wi_stop(sc, 1); - WI_UNLOCK(sc); return (0); } @@ -567,12 +593,12 @@ void wi_intr(void *arg) { struct wi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; u_int16_t status; WI_LOCK(sc); - if (sc->wi_gone || !sc->sc_enabled || - (sc->sc_flags & WI_FLAGS_RUNNING) == 0) { + if (sc->wi_gone || !sc->sc_enabled || (ifp->if_flags & IFF_UP) == 0) { CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); WI_UNLOCK(sc); @@ -591,8 +617,9 @@ wi_intr(void *arg) wi_tx_ex_intr(sc); if (status & WI_EV_INFO) wi_info_intr(sc); - if (mbufq_first(&sc->sc_snd) != NULL) - wi_start(sc); + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && + !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + wi_start_locked(ifp); /* Re-enable interrupts. */ CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); @@ -615,7 +642,7 @@ wi_enable(struct wi_softc *sc) static int wi_setup_locked(struct wi_softc *sc, int porttype, int mode, - const uint8_t mac[IEEE80211_ADDR_LEN]) + uint8_t mac[IEEE80211_ADDR_LEN]) { int i; @@ -649,25 +676,26 @@ wi_setup_locked(struct wi_softc *sc, int porttype, int mode, return 0; } -void -wi_init(struct wi_softc *sc) +static void +wi_init_locked(struct wi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int wasenabled; WI_LOCK_ASSERT(sc); wasenabled = sc->sc_enabled; if (wasenabled) - wi_stop(sc, 1); + wi_stop_locked(sc, 1); - if (wi_setup_locked(sc, sc->sc_porttype, 3, - sc->sc_ic.ic_macaddr) != 0) { - device_printf(sc->sc_dev, "interface not running\n"); - wi_stop(sc, 1); + if (wi_setup_locked(sc, sc->sc_porttype, 3, IF_LLADDR(ifp)) != 0) { + if_printf(ifp, "interface not running\n"); + wi_stop_locked(sc, 1); return; } - sc->sc_flags |= WI_FLAGS_RUNNING; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc); @@ -675,8 +703,24 @@ wi_init(struct wi_softc *sc) } void -wi_stop(struct wi_softc *sc, int disable) +wi_init(void *arg) +{ + struct wi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + WI_LOCK(sc); + wi_init_locked(sc); + WI_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void +wi_stop_locked(struct wi_softc *sc, int disable) { + struct ifnet *ifp = sc->sc_ifp; WI_LOCK_ASSERT(sc); @@ -692,13 +736,22 @@ wi_stop(struct wi_softc *sc, int disable) sc->sc_tx_timer = 0; sc->sc_false_syns = 0; - sc->sc_flags &= ~WI_FLAGS_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); +} + +void +wi_stop(struct wi_softc *sc, int disable) +{ + WI_LOCK(sc); + wi_stop_locked(sc, disable); + WI_UNLOCK(sc); } static void wi_set_channel(struct ieee80211com *ic) { - struct wi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wi_softc *sc = ifp->if_softc; DPRINTF(("%s: channel %d, %sscanning\n", __func__, ieee80211_chan2ieee(ic, ic->ic_curchan), @@ -713,7 +766,8 @@ wi_set_channel(struct ieee80211com *ic) static void wi_scan_start(struct ieee80211com *ic) { - struct wi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wi_softc *sc = ifp->if_softc; struct ieee80211_scan_state *ss = ic->ic_scan; DPRINTF(("%s\n", __func__)); @@ -736,7 +790,8 @@ wi_scan_start(struct ieee80211com *ic) static void wi_scan_end(struct ieee80211com *ic) { - struct wi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wi_softc *sc = ifp->if_softc; DPRINTF(("%s: restore port type %d\n", __func__, sc->sc_porttype)); @@ -769,8 +824,9 @@ static int wi_newstate_sta(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; struct ieee80211_node *bss; - struct wi_softc *sc = ic->ic_softc; + struct wi_softc *sc = ifp->if_softc; DPRINTF(("%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], @@ -838,8 +894,9 @@ static int wi_newstate_hostap(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; struct ieee80211_node *bss; - struct wi_softc *sc = ic->ic_softc; + struct wi_softc *sc = ifp->if_softc; int error; DPRINTF(("%s: %s -> %s\n", __func__, @@ -896,30 +953,10 @@ wi_newstate_hostap(struct ieee80211vap *vap, enum ieee80211_state nstate, int ar return error; } -static int -wi_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct wi_softc *sc = ic->ic_softc; - int error; - - WI_LOCK(sc); - if ((sc->sc_flags & WI_FLAGS_RUNNING) == 0) { - WI_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - WI_UNLOCK(sc); - return (error); - } - wi_start(sc); - WI_UNLOCK(sc); - return (0); -} - static void -wi_start(struct wi_softc *sc) +wi_start_locked(struct ifnet *ifp) { + struct wi_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct ieee80211_frame *wh; struct mbuf *m0; @@ -935,8 +972,15 @@ wi_start(struct wi_softc *sc) memset(&frmhdr, 0, sizeof(frmhdr)); cur = sc->sc_txnext; - while (sc->sc_txd[cur].d_len == 0 && - (m0 = mbufq_dequeue(&sc->sc_snd)) != NULL) { + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); + if (m0 == NULL) + break; + if (sc->sc_txd[cur].d_len != 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m0); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif; /* reconstruct 802.3 header */ @@ -985,16 +1029,28 @@ wi_start(struct wi_softc *sc) m_adj(m0, sizeof(struct ieee80211_frame)); frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); ieee80211_free_node(ni); - if (wi_start_tx(sc, &frmhdr, m0)) + if (wi_start_tx(ifp, &frmhdr, m0)) continue; sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } } +static void +wi_start(struct ifnet *ifp) +{ + struct wi_softc *sc = ifp->if_softc; + + WI_LOCK(sc); + wi_start_locked(ifp); + WI_UNLOCK(sc); +} + static int -wi_start_tx(struct wi_softc *sc, struct wi_frame *frmhdr, struct mbuf *m0) +wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr, struct mbuf *m0) { + struct wi_softc *sc = ifp->if_softc; int cur = sc->sc_txnext; int fid, off, error; @@ -1004,13 +1060,13 @@ wi_start_tx(struct wi_softc *sc, struct wi_frame *frmhdr, struct mbuf *m0) || wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0; m_freem(m0); if (error) { - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return -1; } sc->sc_txd[cur].d_len = off; if (sc->sc_txcur == cur) { if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) { - device_printf(sc->sc_dev, "xmit failed\n"); + if_printf(ifp, "xmit failed\n"); sc->sc_txd[cur].d_len = 0; return -1; } @@ -1024,8 +1080,9 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; struct ieee80211vap *vap = ni->ni_vap; - struct wi_softc *sc = ic->ic_softc; + struct wi_softc *sc = ifp->if_softc; struct ieee80211_key *k; struct ieee80211_frame *wh; struct wi_frame frmhdr; @@ -1041,6 +1098,7 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, memset(&frmhdr, 0, sizeof(frmhdr)); cur = sc->sc_txnext; if (sc->sc_txd[cur].d_len != 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; rc = ENOBUFS; goto out; } @@ -1071,7 +1129,7 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, (caddr_t)&frmhdr.wi_whdr); m_adj(m0, sizeof(struct ieee80211_frame)); frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); - if (wi_start_tx(sc, &frmhdr, m0) < 0) { + if (wi_start_tx(ifp, &frmhdr, m0) < 0) { m0 = NULL; rc = EIO; goto out; @@ -1102,7 +1160,7 @@ wi_reset(struct wi_softc *sc) } sc->sc_reset = 1; if (i == WI_INIT_TRIES) { - device_printf(sc->sc_dev, "reset failed\n"); + if_printf(sc->sc_ifp, "reset failed\n"); return error; } @@ -1120,6 +1178,7 @@ static void wi_watchdog(void *arg) { struct wi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; WI_LOCK_ASSERT(sc); @@ -1127,52 +1186,65 @@ wi_watchdog(void *arg) return; if (sc->sc_tx_timer && --sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); - wi_init(sc); + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + wi_init_locked(ifp->if_softc); return; } callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc); } -static void -wi_parent(struct ieee80211com *ic) +static int +wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct wi_softc *sc = ic->ic_softc; - int startall = 0; + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; - WI_LOCK(sc); - /* - * Can't do promisc and hostap at the same time. If all that's - * changing is the promisc flag, try to short-circuit a call to - * wi_init() by just setting PROMISC in the hardware. - */ - if (ic->ic_nrunning > 0) { - if (ic->ic_opmode != IEEE80211_M_HOSTAP && - sc->sc_flags & WI_FLAGS_RUNNING) { - if (ic->ic_promisc > 0 && - (sc->sc_flags & WI_FLAGS_PROMISC) == 0) { - wi_write_val(sc, WI_RID_PROMISC, 1); - sc->sc_flags |= WI_FLAGS_PROMISC; - } else if (ic->ic_promisc == 0 && - (sc->sc_flags & WI_FLAGS_PROMISC) != 0) { - wi_write_val(sc, WI_RID_PROMISC, 0); - sc->sc_flags &= ~WI_FLAGS_PROMISC; + switch (cmd) { + case SIOCSIFFLAGS: + WI_LOCK(sc); + /* + * Can't do promisc and hostap at the same time. If all that's + * changing is the promisc flag, try to short-circuit a call to + * wi_init() by just setting PROMISC in the hardware. + */ + if (ifp->if_flags & IFF_UP) { + if (ic->ic_opmode != IEEE80211_M_HOSTAP && + ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->sc_if_flags) & IFF_PROMISC) { + wi_write_val(sc, WI_RID_PROMISC, + (ifp->if_flags & IFF_PROMISC) != 0); + } else { + wi_init_locked(sc); + startall = 1; + } } else { - wi_init(sc); + wi_init_locked(sc); startall = 1; } } else { - wi_init(sc); - startall = 1; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + wi_stop_locked(sc, 1); + sc->wi_gone = 0; } - } else if (sc->sc_flags & WI_FLAGS_RUNNING) { - wi_stop(sc, 1); - sc->wi_gone = 0; + sc->sc_if_flags = ifp->if_flags; + WI_UNLOCK(sc); + 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; } - WI_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); + return error; } static void @@ -1180,7 +1252,7 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; - struct wi_softc *sc = ic->ic_softc; + struct wi_softc *sc = ic->ic_ifp->if_softc; u_int16_t val; int rate, len; @@ -1208,7 +1280,8 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) static void wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) { - 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; @@ -1222,7 +1295,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) * indicator of the firmware's BSSID. Damp spurious * change-of-BSSID indications. */ - if (ic->ic_promisc > 0 && + if ((ifp->if_flags & IFF_PROMISC) != 0 && !ppsratecheck(&sc->sc_last_syn, &sc->sc_false_syns, WI_MAX_FALSE_SYNS)) return; @@ -1243,7 +1316,8 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) static __noinline void wi_rx_intr(struct wi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wi_frame frmhdr; struct mbuf *m; struct ieee80211_frame *wh; @@ -1258,7 +1332,7 @@ wi_rx_intr(struct wi_softc *sc) /* First read in the frame header */ if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF(("wi_rx_intr: read fid %x failed\n", fid)); return; } @@ -1269,7 +1343,7 @@ wi_rx_intr(struct wi_softc *sc) status = le16toh(frmhdr.wi_status); if (status & WI_STAT_ERRSTAT) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status)); return; } @@ -1284,7 +1358,7 @@ wi_rx_intr(struct wi_softc *sc) if (off + len > MCLBYTES) { if (ic->ic_opmode != IEEE80211_M_MONITOR) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF(("wi_rx_intr: oversized packet\n")); return; } else @@ -1297,7 +1371,7 @@ wi_rx_intr(struct wi_softc *sc) m = m_gethdr(M_NOWAIT, MT_DATA); if (m == NULL) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - counter_u64_add(ic->ic_ierrors, 1); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); DPRINTF(("wi_rx_intr: MGET failed\n")); return; } @@ -1306,6 +1380,7 @@ wi_rx_intr(struct wi_softc *sc) wi_read_bap(sc, fid, sizeof(frmhdr), m->m_data + sizeof(struct ieee80211_frame), len); m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len; + m->m_pkthdr.rcvif = ifp; CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); @@ -1350,6 +1425,7 @@ wi_rx_intr(struct wi_softc *sc) static __noinline void wi_tx_ex_intr(struct wi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; struct wi_frame frmhdr; int fid; @@ -1364,7 +1440,7 @@ wi_tx_ex_intr(struct wi_softc *sc) */ if ((status & WI_TXSTAT_DISCONNECT) == 0) { if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) { - device_printf(sc->sc_dev, "tx failed"); + if_printf(ifp, "tx failed"); if (status & WI_TXSTAT_RET_ERR) printf(", retry limit exceeded"); if (status & WI_TXSTAT_AGED_ERR) @@ -1379,7 +1455,7 @@ wi_tx_ex_intr(struct wi_softc *sc) printf(", status=0x%x", status); printf("\n"); } - counter_u64_add(sc->sc_ic.ic_oerrors, 1); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); } else DPRINTF(("port disconnected\n")); } else @@ -1390,6 +1466,7 @@ wi_tx_ex_intr(struct wi_softc *sc) static __noinline void wi_tx_intr(struct wi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; int fid, cur; if (sc->wi_gone) @@ -1400,17 +1477,19 @@ wi_tx_intr(struct wi_softc *sc) cur = sc->sc_txcur; if (sc->sc_txd[cur].d_fid != fid) { - device_printf(sc->sc_dev, "bad alloc %x != %x, cur %d nxt %d\n", + if_printf(ifp, "bad alloc %x != %x, cur %d nxt %d\n", fid, sc->sc_txd[cur].d_fid, cur, sc->sc_txnext); return; } sc->sc_tx_timer = 0; sc->sc_txd[cur].d_len = 0; sc->sc_txcur = cur = (cur + 1) % sc->sc_ntxbuf; - if (sc->sc_txd[cur].d_len != 0) { + if (sc->sc_txd[cur].d_len == 0) + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + else { if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid, 0, 0)) { - device_printf(sc->sc_dev, "xmit failed\n"); + if_printf(ifp, "xmit failed\n"); sc->sc_txd[cur].d_len = 0; } else { sc->sc_tx_timer = 5; @@ -1421,7 +1500,7 @@ wi_tx_intr(struct wi_softc *sc) static __noinline void wi_info_intr(struct wi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); int i, fid, len, off; u_int16_t ltbuf[2]; @@ -1495,15 +1574,32 @@ finish: CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); } +static uint64_t +wi_get_counter(struct ifnet *ifp, ift_counter cnt) +{ + struct wi_softc *sc; + + sc = if_getsoftc(ifp); + + switch (cnt) { + case IFCOUNTER_COLLISIONS: + return (sc->sc_stats.wi_tx_single_retries + + sc->sc_stats.wi_tx_multi_retries + + sc->sc_stats.wi_tx_retry_limit); + default: + return (if_get_counter_default(ifp, cnt)); + } +} + static int wi_write_multi(struct wi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap; - struct wi_mcast mlist; + struct ifnet *ifp = sc->sc_ifp; int n; + struct ifmultiaddr *ifma; + struct wi_mcast mlist; - if (ic->ic_allmulti > 0 || ic->ic_promisc > 0) { + if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { allmulti: memset(&mlist, 0, sizeof(mlist)); return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, @@ -1511,23 +1607,17 @@ allmulti: } n = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - struct ifnet *ifp; - struct ifmultiaddr *ifma; - - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (n >= 16) - goto allmulti; - IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], - (LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); - n++; - } - if_maddr_runlock(ifp); + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (n >= 16) + goto allmulti; + IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], + (LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); + n++; } + if_maddr_runlock(ifp); return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, IEEE80211_ADDR_LEN * n); } @@ -1548,7 +1638,7 @@ wi_update_promisc(struct ieee80211com *ic) /* XXX handle WEP special case handling? */ wi_write_val(sc, WI_RID_PROMISC, (ic->ic_opmode == IEEE80211_M_MONITOR || - (ic->ic_promisc > 0))); + (ic->ic_ifp->if_flags & IFF_PROMISC))); WI_UNLOCK(sc); } @@ -1847,7 +1937,7 @@ wi_read_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) } static int -wi_write_bap(struct wi_softc *sc, int id, int off, const void *buf, int buflen) +wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) { int error, cnt; @@ -1859,7 +1949,7 @@ wi_write_bap(struct wi_softc *sc, int id, int off, const void *buf, int buflen) return error; } cnt = (buflen + 1) / 2; - CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, (const uint16_t *)buf, cnt); + CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, (u_int16_t *)buf, cnt); sc->sc_bap_off += cnt * 2; return 0; @@ -1949,7 +2039,7 @@ wi_read_rid(struct wi_softc *sc, int rid, void *buf, int *buflenp) } static int -wi_write_rid(struct wi_softc *sc, int rid, const void *buf, int buflen) +wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen) { int error; u_int16_t ltbuf[2]; diff --git a/sys/dev/wi/if_wi_pccard.c b/sys/dev/wi/if_wi_pccard.c index 414dc20d..fd70e77 100644 --- a/sys/dev/wi/if_wi_pccard.c +++ b/sys/dev/wi/if_wi_pccard.c @@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/socket.h> #include <sys/systm.h> -#include <sys/mbuf.h> #include <sys/module.h> #include <sys/bus.h> diff --git a/sys/dev/wi/if_wi_pci.c b/sys/dev/wi/if_wi_pci.c index b218c24..198c599 100644 --- a/sys/dev/wi/if_wi_pci.c +++ b/sys/dev/wi/if_wi_pci.c @@ -238,9 +238,7 @@ wi_pci_suspend(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - WI_LOCK(sc); wi_stop(sc, 1); - WI_UNLOCK(sc); return (0); } @@ -249,15 +247,16 @@ static int wi_pci_resume(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; - WI_LOCK(sc); - if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { + if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) return (0); - WI_UNLOCK(sc); + + if (ifp->if_flags & IFF_UP) { + ifp->if_init(ifp->if_softc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ifp->if_start(ifp); } - if (ic->ic_nrunning > 0) - wi_init(sc); - WI_UNLOCK(sc); + return (0); } diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index 9b668cc..f163744 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -68,8 +68,7 @@ struct wi_vap { #define WI_VAP(vap) ((struct wi_vap *)(vap)) struct wi_softc { - struct ieee80211com sc_ic; - struct mbufq sc_snd; + struct ifnet *sc_ifp; device_t sc_dev; struct mtx sc_mtx; struct callout sc_watchdog; @@ -108,6 +107,7 @@ struct wi_softc { int wi_cmd_count; int sc_flags; + int sc_if_flags; int sc_bap_id; int sc_bap_off; @@ -152,8 +152,6 @@ struct wi_softc { #define WI_FLAGS_HAS_ROAMING 0x0020 #define WI_FLAGS_HAS_FRAGTHR 0x0200 #define WI_FLAGS_HAS_DBMADJUST 0x0400 -#define WI_FLAGS_RUNNING 0x0800 -#define WI_FLAGS_PROMISC 0x1000 struct wi_card_ident { u_int16_t card_id; @@ -182,7 +180,7 @@ int wi_shutdown(device_t); int wi_alloc(device_t, int); void wi_free(device_t); extern devclass_t wi_devclass; +void wi_init(void *); void wi_intr(void *); int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); void wi_stop(struct wi_softc *, int); -void wi_init(struct wi_softc *); diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index 01ce3e4..3440605 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -205,12 +205,12 @@ static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, const struct ieee80211_bpf_params *); static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static int wpi_transmit(struct ieee80211com *, struct mbuf *); -static void wpi_start(void *, int); +static void wpi_start(struct ifnet *); +static void wpi_start_task(void *, int); static void wpi_watchdog_rfkill(void *); static void wpi_scan_timeout(void *); static void wpi_tx_timeout(void *); -static void wpi_parent(struct ieee80211com *); +static int wpi_ioctl(struct ifnet *, u_long, caddr_t); static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); static int wpi_mrr_setup(struct wpi_softc *); static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); @@ -272,7 +272,7 @@ static int wpi_hw_init(struct wpi_softc *); static void wpi_hw_stop(struct wpi_softc *); static void wpi_radio_on(void *, int); static void wpi_radio_off(void *, int); -static int wpi_init(struct wpi_softc *); +static void wpi_init(void *); static void wpi_stop_locked(struct wpi_softc *); static void wpi_stop(struct wpi_softc *); static void wpi_scan_start(struct ieee80211com *); @@ -329,11 +329,13 @@ wpi_attach(device_t dev) { struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); struct ieee80211com *ic; + struct ifnet *ifp; int i, error, rid; #ifdef WPI_DEBUG int supportsa = 1; const struct wpi_ident *ident; #endif + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; @@ -443,7 +445,14 @@ wpi_attach(device_t dev) /* Clear pending interrupts. */ WPI_WRITE(sc, WPI_INT, 0xffffffff); - ic = &sc->sc_ic; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + goto fail; + } + + 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 */ @@ -472,7 +481,7 @@ wpi_attach(device_t dev) * Read in the eeprom and also setup the channels for * net80211. We don't set the rates as net80211 does this for us */ - if ((error = wpi_read_eeprom(sc, ic->ic_macaddr)) != 0) { + if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { device_printf(dev, "could not read EEPROM, error %d\n", error); goto fail; @@ -494,12 +503,20 @@ wpi_attach(device_t dev) } #endif - ieee80211_ifattach(ic); + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = wpi_init; + ifp->if_ioctl = wpi_ioctl; + ifp->if_start = wpi_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + ieee80211_ifattach(ic, macaddr); ic->ic_vap_create = wpi_vap_create; ic->ic_vap_delete = wpi_vap_delete; - ic->ic_parent = wpi_parent; ic->ic_raw_xmit = wpi_raw_xmit; - ic->ic_transmit = wpi_transmit; ic->ic_node_alloc = wpi_node_alloc; sc->sc_node_free = ic->ic_node_free; ic->ic_node_free = wpi_node_free; @@ -526,7 +543,7 @@ wpi_attach(device_t dev) TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); - TASK_INIT(&sc->sc_start_task, 0, wpi_start, sc); + TASK_INIT(&sc->sc_start_task, 0, wpi_start_task, sc); sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, taskqueue_thread_enqueue, &sc->sc_tq); @@ -571,13 +588,14 @@ fail: wpi_detach(dev); static void wpi_radiotap_attach(struct wpi_softc *sc) { - struct wpi_rx_radiotap_header *rxtap = &sc->sc_rxtap; - struct wpi_tx_radiotap_header *txtap = &sc->sc_txtap; - + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - ieee80211_radiotap_attach(&sc->sc_ic, - &txtap->wt_ihdr, sizeof(*txtap), WPI_TX_RADIOTAP_PRESENT, - &rxtap->wr_ihdr, sizeof(*rxtap), WPI_RX_RADIOTAP_PRESENT); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + WPI_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + WPI_RX_RADIOTAP_PRESENT); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); } @@ -628,9 +646,12 @@ wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - wvp = malloc(sizeof(struct wpi_vap), M_80211_VAP, M_WAITOK | M_ZERO); + wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (wvp == NULL) + return NULL; vap = &wvp->wv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { WPI_VAP_LOCK_INIT(wvp); @@ -650,7 +671,7 @@ wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* Complete setup. */ ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -679,21 +700,22 @@ static int wpi_detach(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; int qid; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (ic->ic_vap_create == wpi_vap_create) { + if (ifp != NULL) { + ic = ifp->if_l2com; + ieee80211_draintask(ic, &sc->sc_radioon_task); ieee80211_draintask(ic, &sc->sc_start_task); wpi_stop(sc); - if (sc->sc_tq != NULL) { - taskqueue_drain_all(sc->sc_tq); - taskqueue_free(sc->sc_tq); - } + taskqueue_drain_all(sc->sc_tq); + taskqueue_free(sc->sc_tq); callout_drain(&sc->watchdog_rfkill); callout_drain(&sc->tx_timeout); @@ -726,6 +748,9 @@ wpi_detach(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), sc->mem); + if (ifp != NULL) + if_free(ifp); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); WPI_TXQ_STATE_LOCK_DESTROY(sc); WPI_TXQ_LOCK_DESTROY(sc); @@ -749,7 +774,7 @@ static int wpi_suspend(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; ieee80211_suspend_all(ic); return 0; @@ -759,7 +784,7 @@ static int wpi_resume(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); @@ -1166,7 +1191,6 @@ wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) ring->queued = 0; ring->cur = 0; ring->update = 0; - mbufq_init(&ring->snd, ifqmaxlen); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); @@ -1294,7 +1318,6 @@ wpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) memset(ring->desc, 0, ring->desc_dma.size); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); - mbufq_drain(&ring->snd); sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; @@ -1425,7 +1448,8 @@ wpi_eeprom_channel_flags(struct wpi_eeprom_chan *channel) static void wpi_read_eeprom_band(struct wpi_softc *sc, int n) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; const struct wpi_chan_band *band = &wpi_bands[n]; struct ieee80211_channel *c; @@ -1482,7 +1506,8 @@ wpi_read_eeprom_band(struct wpi_softc *sc, int n) static int wpi_read_eeprom_channels(struct wpi_softc *sc, int n) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct wpi_chan_band *band = &wpi_bands[n]; int error; @@ -1524,7 +1549,8 @@ static int wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, int nchan, struct ieee80211_channel chans[]) { - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; int i; for (i = 0; i < nchan; i++) { @@ -1533,7 +1559,8 @@ wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, channel = wpi_find_eeprom_channel(sc, c); if (channel == NULL) { - ic_printf(ic, "%s: invalid channel %u freq %u/0x%x\n", + if_printf(ic->ic_ifp, + "%s: invalid channel %u freq %u/0x%x\n", __func__, c->ic_ieee, c->ic_freq, c->ic_flags); return EINVAL; } @@ -1645,7 +1672,8 @@ wpi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) static void wpi_node_free(struct ieee80211_node *ni) { - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct ieee80211com *ic = ni->ni_ic; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); if (wn->id != WPI_ID_UNDEFINED) { @@ -1672,7 +1700,7 @@ wpi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = vap->iv_ic->ic_softc; + struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct wpi_vap *wvp = WPI_VAP(vap); uint64_t ni_tstamp, rx_tstamp; @@ -1716,7 +1744,7 @@ wpi_restore_node(void *arg, struct ieee80211_node *ni) static void wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* Set group keys once. */ WPI_NT_LOCK(sc); @@ -1735,20 +1763,12 @@ wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct wpi_vap *wvp = WPI_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; int error = 0; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - WPI_TXQ_LOCK(sc); - if (nstate > IEEE80211_S_INIT && sc->sc_running == 0) { - DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); - WPI_TXQ_UNLOCK(sc); - - return ENXIO; - } - WPI_TXQ_UNLOCK(sc); - DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); @@ -1917,7 +1937,8 @@ static void wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, struct wpi_rx_data *data) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_rx_ring *ring = &sc->rxq; struct wpi_rx_stat *stat; struct wpi_rx_head *head; @@ -1998,6 +2019,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ + m->m_pkthdr.rcvif = ifp; m->m_data = (caddr_t)(head + 1); m->m_pkthdr.len = m->m_len = len; @@ -2051,7 +2073,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, fail2: m_freem(m); -fail1: counter_u64_add(ic->ic_ierrors, 1); +fail1: if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); } static void @@ -2064,6 +2086,7 @@ wpi_rx_statistics(struct wpi_softc *sc, struct wpi_rx_desc *desc, static void wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) { + struct ifnet *ifp = sc->sc_ifp; struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; struct wpi_tx_data *data = &ring->data[desc->idx]; struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); @@ -2096,11 +2119,14 @@ wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) * Update rate control statistics for the node. */ if (status & WPI_TX_STATUS_FAIL) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); - } else + } else { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); + } ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); @@ -2109,10 +2135,17 @@ wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) if (ring->queued > 0) { callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); - if ((sc->qfullmsk & (1 << ring->qid)) != 0 && - ring->queued < WPI_TX_RING_LOMARK) { + if (sc->qfullmsk != 0 && + ring->queued < WPI_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); - ieee80211_runtask(ic, &sc->sc_start_task); + IF_LOCK(&ifp->if_snd); + if (sc->qfullmsk == 0 && + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); + ieee80211_runtask(ic, &sc->sc_start_task); + } else + IF_UNLOCK(&ifp->if_snd); } } else callout_stop(&sc->tx_timeout); @@ -2170,7 +2203,8 @@ wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) static void wpi_notif_intr(struct wpi_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); uint32_t hw; @@ -2205,7 +2239,7 @@ wpi_notif_intr(struct wpi_softc *sc) /* An 802.11 frame has been received. */ wpi_rx_done(sc, desc, data); - if (sc->sc_running == 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { /* wpi_stop() was called. */ return; } @@ -2294,7 +2328,6 @@ wpi_notif_intr(struct wpi_softc *sc) device_printf(sc->sc_dev, "microcontroller initialization failed\n"); wpi_stop_locked(sc); - return; } /* Save the address of the error log in SRAM. */ sc->errptr = le32toh(uc->errptr); @@ -2525,6 +2558,7 @@ static void wpi_intr(void *arg) { struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t r1, r2; WPI_LOCK(sc); @@ -2574,7 +2608,7 @@ wpi_intr(void *arg) done: /* Re-enable interrupts. */ - if (sc->sc_running) + if (ifp->if_flags & IFF_UP) WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); end: WPI_UNLOCK(sc); @@ -2583,6 +2617,7 @@ end: WPI_UNLOCK(sc); static int wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) { + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_frame *wh; struct wpi_tx_cmd *cmd; struct wpi_tx_data *data; @@ -2598,7 +2633,7 @@ wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (sc->sc_running == 0) { + if (sc->txq_active == 0) { /* wpi_stop() was called */ error = ENETDOWN; goto fail; @@ -2695,8 +2730,14 @@ wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) if (ring->qid < WPI_CMD_QUEUE_NUM) { /* Mark TX ring as full if we reach a certain threshold. */ WPI_TXQ_STATE_LOCK(sc); - if (++ring->queued > WPI_TX_RING_HIMARK) + if (++ring->queued > WPI_TX_RING_HIMARK) { sc->qfullmsk |= 1 << ring->qid; + + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); + } + callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); WPI_TXQ_STATE_UNLOCK(sc); } @@ -2990,47 +3031,24 @@ wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, return wpi_cmd2(sc, &tx_data); } -static __inline int -wpi_tx_ring_is_full(struct wpi_softc *sc, int ac) -{ - struct wpi_tx_ring *ring = &sc->txq[ac]; - int retval; - - WPI_TXQ_STATE_LOCK(sc); - retval = (ring->queued > WPI_TX_RING_HIMARK); - WPI_TXQ_STATE_UNLOCK(sc); - - return retval; -} - -static __inline void -wpi_handle_tx_failure(struct ieee80211_node *ni) -{ - /* NB: m is reclaimed on tx failure */ - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); - ieee80211_free_node(ni); -} - static int wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct wpi_softc *sc = ic->ic_softc; - int ac, error = 0; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; + int error = 0; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - ac = M_WME_GETAC(m); - - WPI_TX_LOCK(sc); - - if (sc->sc_running == 0 || wpi_tx_ring_is_full(sc, ac)) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ieee80211_free_node(ni); m_freem(m); - error = sc->sc_running ? ENOBUFS : ENETDOWN; - goto unlock; + return ENETDOWN; } + WPI_TX_LOCK(sc); if (params == NULL) { /* * Legacy path; interpret frame contents to decide @@ -3044,11 +3062,13 @@ wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, */ error = wpi_tx_data_raw(sc, m, ni, params); } - -unlock: WPI_TX_UNLOCK(sc); + WPI_TX_UNLOCK(sc); if (error != 0) { - wpi_handle_tx_failure(ni); + /* NB: m is reclaimed on tx failure */ + ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); return error; @@ -3059,88 +3079,57 @@ unlock: WPI_TX_UNLOCK(sc); return 0; } -static int -wpi_transmit(struct ieee80211com *ic, struct mbuf *m) +/** + * Process data waiting to be sent on the IFNET output queue + */ +static void +wpi_start(struct ifnet *ifp) { - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ifp->if_softc; struct ieee80211_node *ni; - struct mbufq *sndq; - int ac, error; + struct mbuf *m; WPI_TX_LOCK(sc); DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); - /* Check if interface is up & running. */ - if (sc->sc_running == 0) { - error = ENXIO; - goto unlock; - } - - /* Check for available space. */ - ac = M_WME_GETAC(m); - sndq = &sc->txq[ac].snd; - if (wpi_tx_ring_is_full(sc, ac) || mbufq_len(sndq) != 0) { - /* wpi_tx_done() will dequeue it. */ - error = mbufq_enqueue(sndq, m); - goto unlock; - } + for (;;) { + IF_LOCK(&ifp->if_snd); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + IF_UNLOCK(&ifp->if_snd); + break; + } + IF_UNLOCK(&ifp->if_snd); - error = 0; - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - if (wpi_tx_data(sc, m, ni) != 0) { - wpi_handle_tx_failure(ni); + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + if (wpi_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } } DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); - -unlock: WPI_TX_UNLOCK(sc); - - return (error); + WPI_TX_UNLOCK(sc); } -/** - * Process data waiting to be sent on the output queue - */ static void -wpi_start(void *arg0, int pending) +wpi_start_task(void *arg0, int pending) { struct wpi_softc *sc = arg0; - struct ieee80211_node *ni; - struct mbuf *m; - uint8_t i; - - WPI_TX_LOCK(sc); - if (sc->sc_running == 0) - goto unlock; + struct ifnet *ifp = sc->sc_ifp; - DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); - - for (i = 0; i < WPI_CMD_QUEUE_NUM; i++) { - struct mbufq *sndq = &sc->txq[i].snd; - - for (;;) { - if (wpi_tx_ring_is_full(sc, i)) - break; - - if ((m = mbufq_dequeue(sndq)) == NULL) - break; - - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - if (wpi_tx_data(sc, m, ni) != 0) { - wpi_handle_tx_failure(ni); - } - } - } - - DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); -unlock: WPI_TX_UNLOCK(sc); + wpi_start(ifp); } static void wpi_watchdog_rfkill(void *arg) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); @@ -3157,9 +3146,9 @@ static void wpi_scan_timeout(void *arg) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; - ic_printf(ic, "scan timeout\n"); + if_printf(ifp, "scan timeout\n"); taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); } @@ -3167,28 +3156,44 @@ static void wpi_tx_timeout(void *arg) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; - ic_printf(ic, "device timeout\n"); + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); } -static void -wpi_parent(struct ieee80211com *ic) +static int +wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; - if (ic->ic_nrunning > 0) { - if (wpi_init(sc) == 0) { - ieee80211_notify_radio(ic, 1); - ieee80211_start_all(ic); - } else { - ieee80211_notify_radio(ic, 0); - ieee80211_stop(vap); - } - } else - wpi_stop(sc); + switch (cmd) { + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + wpi_init(sc); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 && + vap != NULL) + ieee80211_stop(vap); + } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + wpi_stop(sc); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + default: + error = EINVAL; + break; + } + return error; } /* @@ -3210,13 +3215,9 @@ wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (sc->sc_running == 0) { + if (sc->txq_active == 0) { /* wpi_stop() was called */ - if (code == WPI_CMD_SCAN) - error = ENETDOWN; - else - error = 0; - + error = 0; goto fail; } @@ -3282,7 +3283,10 @@ wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, WPI_TXQ_UNLOCK(sc); - return async ? 0 : mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); + if (async) + return 0; + + return mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); @@ -3297,7 +3301,8 @@ fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); static int wpi_mrr_setup(struct wpi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_mrr_setup mrr; int i, error; @@ -3394,13 +3399,14 @@ wpi_add_node(struct wpi_softc *sc, struct ieee80211_node *ni) static int wpi_add_broadcast_node(struct wpi_softc *sc, int async) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_node_info node; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); memset(&node, 0, sizeof node); - IEEE80211_ADDR_COPY(node.macaddr, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); node.id = WPI_ID_BROADCAST; node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; @@ -3486,7 +3492,7 @@ static int wpi_updateedca(struct ieee80211com *ic) { #define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_edca_params cmd; int aci, error; @@ -3520,7 +3526,8 @@ wpi_updateedca(struct ieee80211com *ic) static void wpi_set_promisc(struct wpi_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); uint32_t promisc_filter; @@ -3528,7 +3535,7 @@ wpi_set_promisc(struct wpi_softc *sc) if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) promisc_filter |= WPI_FILTER_PROMISC; - if (ic->ic_promisc > 0) + if (ifp->if_flags & IFF_PROMISC) sc->rxon.filter |= htole32(promisc_filter); else sc->rxon.filter &= ~htole32(promisc_filter); @@ -3893,7 +3900,8 @@ wpi_send_rxon(struct wpi_softc *sc, int assoc, int async) static int wpi_config(struct wpi_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_channel *c = ic->ic_curchan; int error; @@ -4003,7 +4011,7 @@ wpi_get_active_dwell_time(struct wpi_softc *sc, static uint16_t wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); int bintval = 0; @@ -4060,7 +4068,8 @@ wpi_get_scan_pause_time(uint32_t time, uint16_t bintval) static int wpi_scan(struct wpi_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 ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211vap *vap = ss->ss_vap; struct wpi_scan_hdr *hdr; @@ -4162,9 +4171,11 @@ wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; - IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); - IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); + *(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ + *(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ frm = (uint8_t *)(wh + 1); frm = ieee80211_add_ssid(frm, NULL, 0); @@ -4195,6 +4206,7 @@ wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) /* * Calculate the active/passive dwell times. */ + dwell_active = wpi_get_active_dwell_time(sc, c, nssid); dwell_passive = wpi_get_passive_dwell_time(sc, c); @@ -4312,7 +4324,7 @@ wpi_config_beacon(struct wpi_vap *wvp) struct ieee80211com *ic = wvp->wv_vap.iv_ic; struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; struct wpi_buf *bcn = &wvp->wv_bcbuf; - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; struct ieee80211_tim_ie *tie; struct mbuf *m; @@ -4394,7 +4406,7 @@ wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) static void wpi_update_beacon(struct ieee80211vap *vap, int item) { - struct wpi_softc *sc = vap->iv_ic->ic_softc; + struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct wpi_vap *wvp = WPI_VAP(vap); struct wpi_buf *bcn = &wvp->wv_bcbuf; struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; @@ -4436,7 +4448,7 @@ static void wpi_newassoc(struct ieee80211_node *ni, int isnew) { struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); int error; @@ -4563,7 +4575,7 @@ wpi_load_key(struct ieee80211_node *ni, const struct ieee80211_key *k) { const struct ieee80211_cipher *cip = k->wk_cipher; struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); struct wpi_node_info node; uint16_t kflags; @@ -4627,7 +4639,7 @@ wpi_load_key_cb(void *arg, struct ieee80211_node *ni) { const struct ieee80211_key *k = arg; struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); int error; @@ -4662,7 +4674,7 @@ static int wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) { struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); struct wpi_node_info node; uint16_t kflags; @@ -4712,7 +4724,7 @@ wpi_del_key_cb(void *arg, struct ieee80211_node *ni) { const struct ieee80211_key *k = arg; struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); int error; @@ -4734,7 +4746,7 @@ wpi_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, int set) { struct ieee80211com *ic = vap->iv_ic; - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_vap *wvp = WPI_VAP(vap); struct ieee80211_node *ni; int error, ni_ref = 0; @@ -5384,29 +5396,34 @@ static void wpi_radio_on(void *arg0, int pending) { struct wpi_softc *sc = arg0; - 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); device_printf(sc->sc_dev, "RF switch: radio enabled\n"); - WPI_LOCK(sc); - callout_stop(&sc->watchdog_rfkill); - WPI_UNLOCK(sc); - - if (vap != NULL) + if (vap != NULL) { + wpi_init(sc); ieee80211_init(vap); + } + + if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL) { + WPI_LOCK(sc); + callout_stop(&sc->watchdog_rfkill); + WPI_UNLOCK(sc); + } } static void wpi_radio_off(void *arg0, int pending) { struct wpi_softc *sc = arg0; - 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); device_printf(sc->sc_dev, "RF switch: radio disabled\n"); - ieee80211_notify_radio(ic, 0); wpi_stop(sc); if (vap != NULL) ieee80211_stop(vap); @@ -5416,16 +5433,19 @@ wpi_radio_off(void *arg0, int pending) WPI_UNLOCK(sc); } -static int -wpi_init(struct wpi_softc *sc) +static void +wpi_init(void *arg) { - int error = 0; + struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + int error; WPI_LOCK(sc); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (sc->sc_running != 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) goto end; /* Check that the radio is not disabled by hardware switch. */ @@ -5434,7 +5454,6 @@ wpi_init(struct wpi_softc *sc) "RF switch: radio disabled (%s)\n", __func__); callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); - error = EINPROGRESS; goto end; } @@ -5443,11 +5462,9 @@ wpi_init(struct wpi_softc *sc) device_printf(sc->sc_dev, "%s: could not read firmware, error %d\n", __func__, error); - goto end; + goto fail; } - sc->sc_running = 1; - /* Initialize hardware and upload firmware. */ error = wpi_hw_init(sc); wpi_unload_firmware(sc); @@ -5459,6 +5476,7 @@ wpi_init(struct wpi_softc *sc) } /* Configure adapter now that it is ready. */ + sc->txq_active = 1; if ((error = wpi_config(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not configure device, error %d\n", __func__, @@ -5466,34 +5484,34 @@ wpi_init(struct wpi_softc *sc) goto fail; } + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + IF_UNLOCK(&ifp->if_snd); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); WPI_UNLOCK(sc); - return 0; + ieee80211_start_all(ic); -fail: wpi_stop_locked(sc); + return; +fail: wpi_stop_locked(sc); end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); WPI_UNLOCK(sc); - - return error; } static void wpi_stop_locked(struct wpi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; WPI_LOCK_ASSERT(sc); - if (sc->sc_running == 0) - return; - - WPI_TX_LOCK(sc); WPI_TXQ_LOCK(sc); - sc->sc_running = 0; + sc->txq_active = 0; WPI_TXQ_UNLOCK(sc); - WPI_TX_UNLOCK(sc); WPI_TXQ_STATE_LOCK(sc); callout_stop(&sc->tx_timeout); @@ -5504,6 +5522,10 @@ wpi_stop_locked(struct wpi_softc *sc) callout_stop(&sc->calib_to); WPI_RXON_UNLOCK(sc); + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + IF_UNLOCK(&ifp->if_snd); + /* Power OFF hardware. */ wpi_hw_stop(sc); } @@ -5522,7 +5544,7 @@ wpi_stop(struct wpi_softc *sc) static void wpi_scan_start(struct ieee80211com *ic) { - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; wpi_set_led(sc, WPI_LED_LINK, 20, 2); } @@ -5533,7 +5555,8 @@ wpi_scan_start(struct ieee80211com *ic) static void wpi_scan_end(struct ieee80211com *ic) { - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); if (vap->iv_state == IEEE80211_S_RUN) @@ -5548,7 +5571,8 @@ static void wpi_set_channel(struct ieee80211com *ic) { const struct ieee80211_channel *c = ic->ic_curchan; - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; int error; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); @@ -5594,7 +5618,7 @@ wpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = vap->iv_ic; - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; int error; WPI_RXON_LOCK(sc); @@ -5620,18 +5644,19 @@ static void wpi_hw_reset(void *arg, int pending) { struct wpi_softc *sc = arg; - 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); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); - ieee80211_notify_radio(ic, 0); if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN)) ieee80211_cancel_scan(vap); wpi_stop(sc); - if (vap != NULL) { + if (vap != NULL) ieee80211_stop(vap); + wpi_init(sc); + if (vap != NULL) ieee80211_init(vap); - } } diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h index 4e1baa5..b783528 100644 --- a/sys/dev/wpi/if_wpivar.h +++ b/sys/dev/wpi/if_wpivar.h @@ -72,7 +72,6 @@ struct wpi_tx_ring { struct wpi_tx_cmd *cmd; struct wpi_tx_data data[WPI_TX_RING_COUNT]; bus_dma_tag_t data_dmat; - struct mbufq snd; int qid; int queued; int cur; @@ -165,15 +164,14 @@ struct wpi_fw_info { struct wpi_softc { device_t sc_dev; + + struct ifnet *sc_ifp; int sc_debug; int sc_flags; #define WPI_PS_PATH (1 << 0) - int sc_running; struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mtx tx_mtx; /* Shared area. */ @@ -183,6 +181,7 @@ struct wpi_softc { struct wpi_tx_ring txq[WPI_NTXQUEUES]; struct mtx txq_mtx; struct mtx txq_state_mtx; + uint32_t txq_active; struct wpi_rx_ring rxq; uint64_t rx_tstamp; diff --git a/sys/dev/wtap/if_wtap.c b/sys/dev/wtap/if_wtap.c index 526ce54..f6dbe77 100644 --- a/sys/dev/wtap/if_wtap.c +++ b/sys/dev/wtap/if_wtap.c @@ -261,7 +261,7 @@ static int wtap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; - struct wtap_softc *sc = ic->ic_softc; + struct wtap_softc *sc = ic->ic_ifp->if_softc; struct wtap_vap *avp = WTAP_VAP(vap); struct ieee80211_node *ni = NULL; int error; @@ -318,7 +318,7 @@ wtap_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct wtap_softc *sc = ic->ic_softc; + struct wtap_softc *sc = ic->ic_ifp->if_softc; struct ieee80211vap *vap; struct wtap_vap *avp; int error; @@ -326,13 +326,15 @@ wtap_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], DWTAP_PRINTF("%s\n", __func__); - avp = malloc(sizeof(struct wtap_vap), M_80211_VAP, M_WAITOK | M_ZERO); + avp = malloc(sizeof(struct wtap_vap), M_80211_VAP, M_NOWAIT | M_ZERO); + if (avp == NULL) + return (NULL); avp->id = sc->id; avp->av_md = sc->sc_md; avp->av_bcinterval = msecs_to_ticks(BEACON_INTRERVAL + 100*sc->id); vap = (struct ieee80211vap *) avp; error = ieee80211_vap_setup(ic, vap, name, unit, IEEE80211_M_MBSS, - flags | IEEE80211_CLONE_NOBEACONS, bssid); + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); if (error) { free(avp, M_80211_VAP); return (NULL); @@ -349,10 +351,9 @@ wtap_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], vap->iv_bmiss = wtap_bmiss; /* complete setup */ - ieee80211_vap_attach(vap, wtap_media_change, ieee80211_media_status, - mac); + ieee80211_vap_attach(vap, wtap_media_change, ieee80211_media_status); avp->av_dev = make_dev(&wtap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, - "%s", (const char *)sc->name); + "%s", (const char *)ic->ic_ifp->if_xname); /* TODO this is a hack to force it to choose the rate we want */ ni = ieee80211_ref_node(vap->iv_bss); @@ -373,16 +374,148 @@ wtap_vap_delete(struct ieee80211vap *vap) free((struct wtap_vap*) vap, M_80211_VAP); } +/* NB: This function is not used. + * I had the problem of the queue + * being empty all the time. + * Maybe I am setting the queue wrong? + */ static void -wtap_parent(struct ieee80211com *ic) +wtap_start(struct ifnet *ifp) { - struct wtap_softc *sc = ic->ic_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifnet *icifp = ic->ic_ifp; + struct wtap_softc *sc = icifp->if_softc; + struct ieee80211_node *ni; + struct mbuf *m; + + DWTAP_PRINTF("my_start, with id=%u\n", sc->id); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->up == 0) + return; + for (;;) { + if(IFQ_IS_EMPTY(&ifp->if_snd)){ + printf("queue empty, just trying to see " + "if the other queue is empty\n"); +#if 0 + printf("queue for id=1, %u\n", + IFQ_IS_EMPTY(&global_mscs[1]->ifp->if_snd)); + printf("queue for id=0, %u\n", + IFQ_IS_EMPTY(&global_mscs[0]->ifp->if_snd)); +#endif + break; + } + IFQ_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) { + printf("error dequeueing from ifp->snd\n"); + break; + } + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + /* + * Check for fragmentation. If this frame + * has been broken up verify we have enough + * buffers to send all the fragments so all + * go out or none... + */ +#if 0 + STAILQ_INIT(&frags); +#endif + if ((m->m_flags & M_FRAG)){ + printf("dont support frags\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + return; + } + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if(wtap_raw_xmit(ni, m, NULL) < 0){ + printf("error raw_xmiting\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + return; + } + } +} + +static int +wtap_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ +#if 0 + DWTAP_PRINTF("%s\n", __func__); + uprintf("%s, command %lu\n", __func__, cmd); +#endif +#define IS_RUNNING(ifp) \ + ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + struct ieee80211com *ic = ifp->if_l2com; + struct wtap_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + //printf("%s: %s\n", __func__, "SIOCSIFFLAGS"); + if (IS_RUNNING(ifp)) { + DWTAP_PRINTF("running\n"); +#if 0 + /* + * To avoid rescanning another access point, + * do not call ath_init() here. Instead, + * only reflect promisc mode settings. + */ + //ath_mode_init(sc); +#endif + } else if (ifp->if_flags & IFF_UP) { + DWTAP_PRINTF("up\n"); + sc->up = 1; +#if 0 + /* + * Beware of being called during attach/detach + * to reset promiscuous mode. In that case we + * will still be marked UP but not RUNNING. + * However trying to re-init the interface + * is the wrong thing to do as we've already + * torn down much of our state. There's + * probably a better way to deal with this. + */ + //if (!sc->sc_invalid) + // ath_init(sc); /* XXX lose error */ +#endif + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ieee80211_start_all(ic); + } else { + DWTAP_PRINTF("stoping\n"); +#if 0 + ath_stop_locked(ifp); +#ifdef notyet + /* XXX must wakeup in places like ath_vap_delete */ + if (!sc->sc_invalid) + ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); +#endif +#endif + } + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: +#if 0 + DWTAP_PRINTF("%s: %s\n", __func__, "SIOCGIFMEDIA|SIOCSIFMEDIA"); +#endif + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCGIFADDR: +#if 0 + DWTAP_PRINTF("%s: %s\n", __func__, "SIOCGIFADDR"); +#endif + error = ether_ioctl(ifp, cmd, data); + break; + default: + DWTAP_PRINTF("%s: %s [%lu]\n", __func__, "EINVAL", cmd); + error = EINVAL; + break; + } + return error; +#undef IS_RUNNING +} + +static void +wtap_init(void *arg){ - if (ic->ic_nrunning > 0) { - sc->up = 1; - ieee80211_start_all(ic); - } else - sc->up = 0; + DWTAP_PRINTF("%s\n", __func__); } static void @@ -448,7 +581,8 @@ wtap_inject(struct wtap_softc *sc, struct mbuf *m) void wtap_rx_deliver(struct wtap_softc *sc, struct mbuf *m) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni; int type; #if 0 @@ -457,9 +591,11 @@ wtap_rx_deliver(struct wtap_softc *sc, struct mbuf *m) DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, m); if (m == NULL) { /* NB: shouldn't happen */ - ic_printf(ic, "%s: no mbuf!\n", __func__); + if_printf(ifp, "%s: no mbuf!\n", __func__); } + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0); /* @@ -484,7 +620,8 @@ static void wtap_rx_proc(void *arg, int npending) { struct wtap_softc *sc = (struct wtap_softc *)arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct mbuf *m; struct ieee80211_node *ni; int type; @@ -507,10 +644,12 @@ wtap_rx_proc(void *arg, int npending) m = bf->m; DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, bf->m); if (m == NULL) { /* NB: shouldn't happen */ - ic_printf(ic, "%s: no mbuf!\n", __func__); + if_printf(ifp, "%s: no mbuf!\n", __func__); free(bf, M_WTAP_RXBUF); return; } + + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); #if 0 ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0); #endif @@ -577,7 +716,7 @@ wtap_update_promisc(struct ieee80211com *ic) } static int -wtap_transmit(struct ieee80211com *ic, struct mbuf *m) +wtap_if_transmit(struct ifnet *ifp, struct mbuf *m) { struct ieee80211_node *ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; @@ -614,7 +753,7 @@ static void wtap_node_free(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - struct wtap_softc *sc = ic->ic_softc; + struct wtap_softc *sc = ic->ic_ifp->if_softc; DWTAP_PRINTF("%s\n", __func__); sc->sc_node_free(ni); @@ -623,17 +762,41 @@ wtap_node_free(struct ieee80211_node *ni) int32_t wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp; + struct ieee80211com *ic; + char wtap_name[] = {'w','T','a','p',sc->id, + '_','t','a','s','k','q','\0'}; DWTAP_PRINTF("%s\n", __func__); + ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + printf("can not if_alloc()\n"); + return -1; + } + ic = ifp->if_l2com; + if_initname(ifp, "wtap", sc->id); + + sc->sc_ifp = ifp; sc->up = 0; + STAILQ_INIT(&sc->sc_rxbuf); - sc->sc_tq = taskqueue_create("wtap_taskq", M_NOWAIT | M_ZERO, + sc->sc_tq = taskqueue_create(wtap_name, M_NOWAIT | M_ZERO, taskqueue_thread_enqueue, &sc->sc_tq); - taskqueue_start_threads(&sc->sc_tq, 1, PI_SOFT, "%s taskQ", sc->name); + taskqueue_start_threads(&sc->sc_tq, 1, PI_SOFT, "%s taskQ", + ifp->if_xname); TASK_INIT(&sc->sc_rxtask, 0, wtap_rx_proc, sc); + ifp->if_softc = sc; + ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_start = wtap_start; + ifp->if_ioctl = wtap_ioctl; + ifp->if_init = wtap_init; + 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 = sc->name; ic->ic_phytype = IEEE80211_T_DS; @@ -652,8 +815,17 @@ wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr) ic->ic_channels[0].ic_flags = IEEE80211_CHAN_B; ic->ic_channels[0].ic_freq = 2412; - IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); - ieee80211_ifattach(ic); + ieee80211_ifattach(ic, macaddr); + +#if 0 + /* new prototype hook-ups */ + msc->if_input = ifp->if_input; + ifp->if_input = myath_if_input; + msc->if_output = ifp->if_output; + ifp->if_output = myath_if_output; +#endif + sc->if_transmit = ifp->if_transmit; + ifp->if_transmit = wtap_if_transmit; /* override default methods */ ic->ic_newassoc = wtap_newassoc; @@ -663,14 +835,15 @@ wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr) ic->ic_raw_xmit = wtap_raw_xmit; ic->ic_update_mcast = wtap_update_mcast; ic->ic_update_promisc = wtap_update_promisc; - ic->ic_transmit = wtap_transmit; - ic->ic_parent = wtap_parent; sc->sc_node_alloc = ic->ic_node_alloc; ic->ic_node_alloc = wtap_node_alloc; sc->sc_node_free = ic->ic_node_free; ic->ic_node_free = wtap_node_free; +#if 0 + ic->ic_node_getsignal = myath_node_getsignal; +#endif ic->ic_scan_start = wtap_scan_start; ic->ic_scan_end = wtap_scan_end; ic->ic_set_channel = wtap_set_channel; @@ -709,11 +882,13 @@ wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr) int32_t wtap_detach(struct wtap_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DWTAP_PRINTF("%s\n", __func__); ieee80211_ageq_drain(&ic->ic_stageq); ieee80211_ifdetach(ic); + if_free(ifp); return 0; } diff --git a/sys/dev/wtap/if_wtapvar.h b/sys/dev/wtap/if_wtapvar.h index 04a1818..a886be9 100644 --- a/sys/dev/wtap/if_wtapvar.h +++ b/sys/dev/wtap/if_wtapvar.h @@ -130,14 +130,18 @@ struct wtap_vap { struct taskqueue; struct wtap_softc { - struct ieee80211com sc_ic; char name[7]; /* wtapXX\0 */ int32_t id; int32_t up; + struct ifnet *sc_ifp; /* interface common */ struct wtap_medium *sc_md; /* interface medium */ struct ieee80211_node* (* sc_node_alloc) (struct ieee80211vap *, const uint8_t [IEEE80211_ADDR_LEN]); void (*sc_node_free)(struct ieee80211_node *); + int (*if_output) /* output routine (enqueue) */ + (struct ifnet *, struct mbuf *, struct sockaddr *, struct route *); + void (*if_input) (struct ifnet *, struct mbuf *);/* from h/w driver */ + int (*if_transmit)(struct ifnet *, struct mbuf *);/* output routine */ struct mtx sc_mtx; /* master lock (recursive) */ struct taskqueue *sc_tq; /* private task queue */ wtap_bufhead sc_rxbuf; /* receive buffer */ diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 39e03ea..3902227 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/kernel.h> #include <sys/socket.h> -#include <sys/sbuf.h> #include <machine/stdarg.h> @@ -92,6 +91,8 @@ static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag); static int ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media, int caps, int addsta, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat); +static void ieee80211com_media_status(struct ifnet *, struct ifmediareq *); +static int ieee80211com_media_change(struct ifnet *); static int media_status(enum ieee80211_opmode, const struct ieee80211_channel *); static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter); @@ -120,7 +121,7 @@ static const struct ieee80211_rateset ieee80211_rateset_11g = * all available channels as active, and pick * a default channel if not already specified. */ -void +static void ieee80211_chan_init(struct ieee80211com *ic) { #define DEFAULTRATES(m, def) do { \ @@ -237,6 +238,29 @@ null_update_promisc(struct ieee80211com *ic) ic_printf(ic, "need promiscuous mode update callback\n"); } +static int +null_transmit(struct ifnet *ifp, struct mbuf *m) +{ + m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + return EACCES; /* XXX EIO/EPERM? */ +} + +static int +null_output(struct ifnet *ifp, struct mbuf *m, + const struct sockaddr *dst, struct route *ro) +{ + if_printf(ifp, "discard raw packet\n"); + return null_transmit(ifp, m); +} + +static void +null_input(struct ifnet *ifp, struct mbuf *m) +{ + if_printf(ifp, "if_input should not be called\n"); + m_freem(m); +} + static void null_update_chw(struct ieee80211com *ic) { @@ -257,43 +281,19 @@ ic_printf(struct ieee80211com *ic, const char * fmt, ...) return (retval); } -static LIST_HEAD(, ieee80211com) ic_head = LIST_HEAD_INITIALIZER(ic_head); -static struct mtx ic_list_mtx; -MTX_SYSINIT(ic_list, &ic_list_mtx, "ieee80211com list", MTX_DEF); - -static int -sysctl_ieee80211coms(SYSCTL_HANDLER_ARGS) -{ - struct ieee80211com *ic; - struct sbuf *sb; - char *sp; - int error; - - sb = sbuf_new_auto(); - sp = ""; - mtx_lock(&ic_list_mtx); - LIST_FOREACH(ic, &ic_head, ic_next) { - sbuf_printf(sb, "%s%s", sp, ic->ic_name); - sp = " "; - } - mtx_unlock(&ic_list_mtx); - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); - sbuf_delete(sb); - return (error); -} - -SYSCTL_PROC(_net_wlan, OID_AUTO, devices, - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, - sysctl_ieee80211coms, "A", "names of available 802.11 devices"); - /* * Attach/setup the common net80211 state. Called by * the driver on attach to prior to creating any vap's. */ void -ieee80211_ifattach(struct ieee80211com *ic) +ieee80211_ifattach(struct ieee80211com *ic, + const uint8_t macaddr[IEEE80211_ADDR_LEN]) { + struct ifnet *ifp = ic->ic_ifp; + struct sockaddr_dl *sdl; + struct ifaddr *ifa; + + KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type)); IEEE80211_LOCK_INIT(ic, ic->ic_name); IEEE80211_TX_LOCK_INIT(ic, ic->ic_name); @@ -311,7 +311,7 @@ ieee80211_ifattach(struct ieee80211com *ic) * available channels as active, and pick a default * channel if not already specified. */ - ieee80211_chan_init(ic); + ieee80211_media_init(ic); ic->ic_update_mcast = null_update_mcast; ic->ic_update_promisc = null_update_promisc; @@ -336,9 +336,28 @@ ieee80211_ifattach(struct ieee80211com *ic) ieee80211_sysctl_attach(ic); - mtx_lock(&ic_list_mtx); - LIST_INSERT_HEAD(&ic_head, ic, ic_next); - mtx_unlock(&ic_list_mtx); + ifp->if_addrlen = IEEE80211_ADDR_LEN; + ifp->if_hdrlen = 0; + + CURVNET_SET(vnet0); + + if_attach(ifp); + + ifp->if_mtu = IEEE80211_MTU_MAX; + ifp->if_broadcastaddr = ieee80211broadcastaddr; + ifp->if_output = null_output; + ifp->if_input = null_input; /* just in case */ + ifp->if_resolvemulti = NULL; /* NB: callers check */ + + ifa = ifaddr_byindex(ifp->if_index); + KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; /* XXX IFT_IEEE80211? */ + sdl->sdl_alen = IEEE80211_ADDR_LEN; + IEEE80211_ADDR_COPY(LLADDR(sdl), macaddr); + ifa_free(ifa); + + CURVNET_RESTORE(); } /* @@ -350,11 +369,16 @@ ieee80211_ifattach(struct ieee80211com *ic) void ieee80211_ifdetach(struct ieee80211com *ic) { + struct ifnet *ifp = ic->ic_ifp; struct ieee80211vap *vap; - mtx_lock(&ic_list_mtx); - LIST_REMOVE(ic, ic_next); - mtx_unlock(&ic_list_mtx); + /* + * This detaches the main interface, but not the vaps. + * Each VAP may be in a separate VIMAGE. + */ + CURVNET_SET(ifp->if_vnet); + if_detach(ifp); + CURVNET_RESTORE(); /* * The VAP is responsible for setting and clearing @@ -378,6 +402,8 @@ ieee80211_ifdetach(struct ieee80211com *ic) ieee80211_power_detach(ic); ieee80211_node_detach(ic); + /* XXX VNET needed? */ + ifmedia_removeall(&ic->ic_media); counter_u64_free(ic->ic_ierrors); counter_u64_free(ic->ic_oerrors); @@ -386,20 +412,6 @@ ieee80211_ifdetach(struct ieee80211com *ic) IEEE80211_LOCK_DESTROY(ic); } -struct ieee80211com * -ieee80211_find_com(const char *name) -{ - struct ieee80211com *ic; - - mtx_lock(&ic_list_mtx); - LIST_FOREACH(ic, &ic_head, ic_next) - if (strcmp(ic->ic_name, name) == 0) - break; - mtx_unlock(&ic_list_mtx); - - return (ic); -} - /* * Default reset method for use with the ioctl support. This * method is invoked after any state change in the 802.11 @@ -448,7 +460,8 @@ ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt) int ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, - int flags, const uint8_t bssid[IEEE80211_ADDR_LEN]) + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t macaddr[IEEE80211_ADDR_LEN]) { struct ifnet *ifp; @@ -477,7 +490,6 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, vap->iv_htextcaps = ic->ic_htextcaps; vap->iv_opmode = opmode; vap->iv_caps |= ieee80211_opcap[opmode]; - vap->iv_myaddr = ic->ic_macaddr; switch (opmode) { case IEEE80211_M_WDS: /* @@ -544,6 +556,8 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, */ vap->iv_reset = default_reset; + IEEE80211_ADDR_COPY(vap->iv_myaddr, macaddr); + ieee80211_sysctl_vattach(vap); ieee80211_crypto_vattach(vap); ieee80211_node_vattach(vap); @@ -567,8 +581,8 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, * from this call the vap is ready for use. */ int -ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, - ifm_stat_cb_t media_stat, const uint8_t macaddr[IEEE80211_ADDR_LEN]) +ieee80211_vap_attach(struct ieee80211vap *vap, + ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) { struct ifnet *ifp = vap->iv_ifp; struct ieee80211com *ic = vap->iv_ic; @@ -596,8 +610,7 @@ ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, if (maxrate) ifp->if_baudrate = IF_Mbps(maxrate); - ether_ifattach(ifp, macaddr); - vap->iv_myaddr = IF_LLADDR(ifp); + ether_ifattach(ifp, vap->iv_myaddr); /* hook output method setup by ether_ifattach */ vap->iv_output = ifp->if_output; ifp->if_output = ieee80211_output; @@ -613,6 +626,8 @@ ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); + ieee80211_syncifflag_locked(ic, IFF_PROMISC); + ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); IEEE80211_UNLOCK(ic); return 1; @@ -662,10 +677,8 @@ ieee80211_vap_detach(struct ieee80211vap *vap) ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); /* NB: this handles the bpfdetach done below */ ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); - if (vap->iv_ifflags & IFF_PROMISC) - ieee80211_promisc(vap, false); - if (vap->iv_ifflags & IFF_ALLMULTI) - ieee80211_allmulti(vap, false); + ieee80211_syncifflag_locked(ic, IFF_PROMISC); + ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); IEEE80211_UNLOCK(ic); ifmedia_removeall(&vap->iv_media); @@ -690,57 +703,49 @@ ieee80211_vap_detach(struct ieee80211vap *vap) } /* - * Count number of vaps in promisc, and issue promisc on - * parent respectively. + * Synchronize flag bit state in the parent ifnet structure + * according to the state of all vap ifnet's. This is used, + * for example, to handle IFF_PROMISC and IFF_ALLMULTI. */ void -ieee80211_promisc(struct ieee80211vap *vap, bool on) +ieee80211_syncifflag_locked(struct ieee80211com *ic, int flag) { - struct ieee80211com *ic = vap->iv_ic; - - /* - * XXX the bridge sets PROMISC but we don't want to - * enable it on the device, discard here so all the - * drivers don't need to special-case it - */ - if (!(vap->iv_opmode == IEEE80211_M_MONITOR || - (vap->iv_opmode == IEEE80211_M_AHDEMO && - (vap->iv_caps & IEEE80211_C_TDMA) == 0))) - return; - - IEEE80211_LOCK(ic); - if (on) { - if (++ic->ic_promisc == 1) - ieee80211_runtask(ic, &ic->ic_promisc_task); - } else { - KASSERT(ic->ic_promisc > 0, ("%s: ic %p not promisc", - __func__, ic)); - if (--ic->ic_promisc == 0) - ieee80211_runtask(ic, &ic->ic_promisc_task); - } - IEEE80211_UNLOCK(ic); -} + struct ifnet *ifp = ic->ic_ifp; + struct ieee80211vap *vap; + int bit, oflags; -/* - * Count number of vaps in allmulti, and issue allmulti on - * parent respectively. - */ -void -ieee80211_allmulti(struct ieee80211vap *vap, bool on) -{ - struct ieee80211com *ic = vap->iv_ic; + IEEE80211_LOCK_ASSERT(ic); - IEEE80211_LOCK(ic); - if (on) { - if (++ic->ic_allmulti == 1) - ieee80211_runtask(ic, &ic->ic_mcast_task); - } else { - KASSERT(ic->ic_allmulti > 0, ("%s: ic %p not allmulti", - __func__, ic)); - if (--ic->ic_allmulti == 0) - ieee80211_runtask(ic, &ic->ic_mcast_task); + bit = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_ifp->if_flags & flag) { + /* + * XXX the bridge sets PROMISC but we don't want to + * enable it on the device, discard here so all the + * drivers don't need to special-case it + */ + if (flag == IFF_PROMISC && + !(vap->iv_opmode == IEEE80211_M_MONITOR || + (vap->iv_opmode == IEEE80211_M_AHDEMO && + (vap->iv_caps & IEEE80211_C_TDMA) == 0))) + continue; + bit = 1; + break; + } + oflags = ifp->if_flags; + if (bit) + ifp->if_flags |= flag; + else + ifp->if_flags &= ~flag; + if ((ifp->if_flags ^ oflags) & flag) { + /* XXX should we return 1/0 and let caller do this? */ + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if (flag == IFF_PROMISC) + ieee80211_runtask(ic, &ic->ic_promisc_task); + else if (flag == IFF_ALLMULTI) + ieee80211_runtask(ic, &ic->ic_mcast_task); + } } - IEEE80211_UNLOCK(ic); } /* @@ -1229,6 +1234,39 @@ ieee80211_media_setup(struct ieee80211com *ic, return maxrate; } +void +ieee80211_media_init(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + int maxrate; + + /* NB: this works because the structure is initialized to zero */ + if (!LIST_EMPTY(&ic->ic_media.ifm_list)) { + /* + * We are re-initializing the channel list; clear + * the existing media state as the media routines + * don't suppress duplicates. + */ + ifmedia_removeall(&ic->ic_media); + } + ieee80211_chan_init(ic); + + /* + * Recalculate media settings in case new channel list changes + * the set of available modes. + */ + maxrate = ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, 1, + ieee80211com_media_change, ieee80211com_media_status); + /* NB: strip explicit mode; we're actually in autoselect */ + ifmedia_set(&ic->ic_media, + media_status(ic->ic_opmode, ic->ic_curchan) &~ + (IFM_MMASK | IFM_IEEE80211_TURBO)); + if (maxrate) + ifp->if_baudrate = IF_Mbps(maxrate); + + /* XXX need to propagate new media settings to vap's */ +} + /* XXX inline or eliminate? */ const struct ieee80211_rateset * ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) @@ -1357,6 +1395,15 @@ media2mode(const struct ifmedia_entry *ime, uint32_t flags, uint16_t *mode) } /* + * Handle a media change request on the underlying interface. + */ +int +ieee80211com_media_change(struct ifnet *ifp) +{ + return EINVAL; +} + +/* * Handle a media change request on the vap interface. */ int @@ -1433,6 +1480,23 @@ media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan) return status; } +static void +ieee80211com_media_status(struct ifnet *ifp, struct ifmediareq *imr) +{ + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap; + + imr->ifm_status = IFM_AVALID; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_ifp->if_flags & IFF_UP) { + imr->ifm_status |= IFM_ACTIVE; + break; + } + imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan); + if (imr->ifm_status & IFM_ACTIVE) + imr->ifm_current = imr->ifm_active; +} + void ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) { diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c index ae4910c..e646cf2 100644 --- a/sys/net80211/ieee80211_ddb.c +++ b/sys/net80211/ieee80211_ddb.c @@ -520,7 +520,7 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta, TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) db_printf(" %s(%p)", vap->iv_ifp->if_xname, vap); db_printf("\n"); - db_printf("\tsoftc %p", ic->ic_softc); + db_printf("\tifp %p(%s)", ic->ic_ifp, ic->ic_ifp->if_xname); db_printf("\tname %s", ic->ic_name); db_printf(" comlock %p", &ic->ic_comlock); db_printf("\n"); @@ -528,6 +528,7 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta, db_printf(" phytype %d", ic->ic_phytype); db_printf(" opmode %s", ieee80211_opmode_name[ic->ic_opmode]); db_printf("\n"); + db_printf("\tmedia %p", &ic->ic_media); db_printf(" inact %p", &ic->ic_inact); db_printf("\n"); diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c index 9a8e941..3af75df 100644 --- a/sys/net80211/ieee80211_freebsd.c +++ b/sys/net80211/ieee80211_freebsd.c @@ -69,27 +69,58 @@ static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); static const char wlanname[] = "wlan"; static struct if_clone *wlan_cloner; +/* + * Allocate/free com structure in conjunction with ifnet; + * these routines are registered with if_register_com_alloc + * below and are called automatically by the ifnet code + * when the ifnet of the parent device is created. + */ +static void * +wlan_alloc(u_char type, struct ifnet *ifp) +{ + struct ieee80211com *ic; + + ic = IEEE80211_MALLOC(sizeof(struct ieee80211com), M_80211_COM, + IEEE80211_M_WAITOK | IEEE80211_M_ZERO); + ic->ic_ifp = ifp; + + return (ic); +} + +static void +wlan_free(void *ic, u_char type) +{ + IEEE80211_FREE(ic, M_80211_COM); +} + static int wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) { struct ieee80211_clone_params cp; struct ieee80211vap *vap; struct ieee80211com *ic; + struct ifnet *ifp; int error; error = copyin(params, &cp, sizeof(cp)); if (error) return error; - ic = ieee80211_find_com(cp.icp_parent); - if (ic == NULL) + ifp = ifunit(cp.icp_parent); + if (ifp == NULL) return ENXIO; + /* XXX move printfs to DIAGNOSTIC before release */ + if (ifp->if_type != IFT_IEEE80211) { + if_printf(ifp, "%s: reject, not an 802.11 device\n", __func__); + return ENXIO; + } if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) { - ic_printf(ic, "%s: invalid opmode %d\n", __func__, - cp.icp_opmode); + if_printf(ifp, "%s: invalid opmode %d\n", + __func__, cp.icp_opmode); return EINVAL; } + ic = ifp->if_l2com; if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) { - ic_printf(ic, "%s mode not supported\n", + if_printf(ifp, "%s mode not supported\n", ieee80211_opmode_name[cp.icp_opmode]); return EOPNOTSUPP; } @@ -100,13 +131,13 @@ wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) (1) #endif ) { - ic_printf(ic, "TDMA not supported\n"); + if_printf(ifp, "TDMA not supported\n"); return EOPNOTSUPP; } vap = ic->ic_vap_create(ic, wlanname, unit, cp.icp_opmode, cp.icp_flags, cp.icp_bssid, cp.icp_flags & IEEE80211_CLONE_MACADDR ? - cp.icp_macaddr : ic->ic_macaddr); + cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp)); return (vap == NULL ? EIO : 0); } @@ -497,19 +528,17 @@ ieee80211_process_callback(struct ieee80211_node *ni, * (the callers will first need modifying.) */ int -ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m) +ieee80211_parent_xmitpkt(struct ieee80211com *ic, + struct mbuf *m) { - int error; - + struct ifnet *parent = ic->ic_ifp; /* * Assert the IC TX lock is held - this enforces the * processing -> queuing order is maintained */ IEEE80211_TX_LOCK_ASSERT(ic); - error = ic->ic_transmit(ic, m); - if (error) - m_freem(m); - return (error); + + return (parent->if_transmit(parent, m)); } /* @@ -807,6 +836,7 @@ ieee80211_load_module(const char *modname) } static eventhandler_tag wlan_bpfevent; +static eventhandler_tag wlan_ifllevent; static void bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach) @@ -834,6 +864,33 @@ bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach) } } +static void +wlan_iflladdr(void *arg __unused, struct ifnet *ifp) +{ + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap, *next; + + if (ifp->if_type != IFT_IEEE80211 || ic == NULL) + return; + + IEEE80211_LOCK(ic); + TAILQ_FOREACH_SAFE(vap, &ic->ic_vaps, iv_next, next) { + /* + * If the MAC address has changed on the parent and it was + * copied to the vap on creation then re-sync. + */ + if (vap->iv_ic == ic && + (vap->iv_flags_ext & IEEE80211_FEXT_UNIQMAC) == 0) { + IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp)); + IEEE80211_UNLOCK(ic); + if_setlladdr(vap->iv_ifp, IF_LLADDR(ifp), + IEEE80211_ADDR_LEN); + IEEE80211_LOCK(ic); + } + } + IEEE80211_UNLOCK(ic); +} + /* * Module glue. * @@ -848,12 +905,17 @@ wlan_modevent(module_t mod, int type, void *unused) printf("wlan: <802.11 Link Layer>\n"); wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track, bpf_track, 0, EVENTHANDLER_PRI_ANY); + wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event, + wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY); wlan_cloner = if_clone_simple(wlanname, wlan_clone_create, wlan_clone_destroy, 0); + if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free); return 0; case MOD_UNLOAD: + if_deregister_com_alloc(IFT_IEEE80211); if_clone_detach(wlan_cloner); EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent); + EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent); return 0; } return EINVAL; diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 1c7ddb9..54ab390 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -1329,12 +1329,13 @@ static int setmlme_dropsta(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], struct mlmeop *mlmeop) { - struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *ni; int error = 0; /* NB: the broadcast address means do 'em all */ - if (!IEEE80211_ADDR_EQ(mac, vap->iv_ifp->if_broadcastaddr)) { + if (!IEEE80211_ADDR_EQ(mac, ic->ic_ifp->if_broadcastaddr)) { IEEE80211_NODE_LOCK(nt); ni = ieee80211_find_node_locked(nt, mac); IEEE80211_NODE_UNLOCK(nt); @@ -2528,9 +2529,14 @@ ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr) static __noinline int ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) { + struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_req sr; /* XXX off stack? */ int error; + /* NB: parent must be running */ + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return ENXIO; + if (ireq->i_len != sizeof(sr)) return EINVAL; error = copyin(ireq->i_data, &sr, sizeof(sr)); @@ -3294,6 +3300,41 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r return error; } +/* + * Rebuild the parent's multicast address list after an add/del + * of a multicast address for a vap. We have no way to tell + * what happened above to optimize the work so we purge the entire + * list and rebuild from scratch. This is way expensive. + * Note also the half-baked workaround for if_addmulti calling + * back to the parent device; there's no way to insert mcast + * entries quietly and/or cheaply. + */ +static void +ieee80211_ioctl_updatemulti(struct ieee80211com *ic) +{ + struct ifnet *parent = ic->ic_ifp; + struct ieee80211vap *vap; + void *ioctl; + + IEEE80211_LOCK(ic); + if_delallmulti(parent); + ioctl = parent->if_ioctl; /* XXX WAR if_allmulti */ + parent->if_ioctl = NULL; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp = vap->iv_ifp; + struct ifmultiaddr *ifma; + + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + (void) if_addmulti(parent, ifma->ifma_addr, NULL); + } + } + parent->if_ioctl = ioctl; + ieee80211_runtask(ic, &ic->ic_mcast_task); + IEEE80211_UNLOCK(ic); +} + int ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -3306,11 +3347,8 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) switch (cmd) { case SIOCSIFFLAGS: IEEE80211_LOCK(ic); - if ((ifp->if_flags ^ vap->iv_ifflags) & IFF_PROMISC) - ieee80211_promisc(vap, ifp->if_flags & IFF_PROMISC); - if ((ifp->if_flags ^ vap->iv_ifflags) & IFF_ALLMULTI) - ieee80211_allmulti(vap, ifp->if_flags & IFF_ALLMULTI); - vap->iv_ifflags = ifp->if_flags; + ieee80211_syncifflag_locked(ic, IFF_PROMISC); + ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); if (ifp->if_flags & IFF_UP) { /* * Bring ourself up unless we're already operational. @@ -3333,7 +3371,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCADDMULTI: case SIOCDELMULTI: - ieee80211_runtask(ic, &ic->ic_mcast_task); + ieee80211_ioctl_updatemulti(ic); break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: @@ -3389,16 +3427,17 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } break; + /* Pass NDIS ioctls up to the driver */ + case SIOCGDRVSPEC: + case SIOCSDRVSPEC: + case SIOCGPRIVATE_0: { + struct ifnet *parent = vap->iv_ic->ic_ifp; + error = parent->if_ioctl(parent, cmd, data); + break; + } default: - /* - * Pass unknown ioctls first to the driver, and if it - * returns ENOTTY, then to the generic Ethernet handler. - */ - if (ic->ic_ioctl != NULL && - (error = ic->ic_ioctl(ic, cmd, data)) != ENOTTY) - break; error = ether_ioctl(ifp, cmd, data); break; } - return (error); + return error; } diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index eb333da1..d11628d 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -254,6 +254,10 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m, /* NB: IFQ_HANDOFF reclaims mbuf */ ieee80211_free_node(ni); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } else { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast); + if_inc_counter(ifp, IFCOUNTER_OBYTES, len); } ic->ic_lastdata = ticks; @@ -426,6 +430,17 @@ ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; + struct ifnet *parent = ic->ic_ifp; + + /* NB: parent must be up and running */ + if (!IFNET_IS_UP_RUNNING(parent)) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, + "%s: ignore queue, parent %s not up+running\n", + __func__, parent->if_xname); + m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + return (ENETDOWN); + } /* * No data frames go out unless we're running. @@ -492,7 +507,6 @@ ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = vap->iv_ic; - int error; /* * Set node - the caller has taken a reference, so ensure @@ -514,10 +528,7 @@ ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, if (params) (void) ieee80211_add_xmit_params(m, params); - error = ic->ic_raw_xmit(ni, m, params); - if (error) - if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 1); - return (error); + return (ic->ic_raw_xmit(ni, m, params)); } /* @@ -3446,15 +3457,6 @@ ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status) { if (ni != NULL) { - struct ifnet *ifp = ni->ni_vap->iv_ifp; - - if (status == 0) { - if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - if (m->m_flags & M_MCAST) - if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); - } else - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (m->m_flags & M_TXCB) ieee80211_process_callback(ni, m, status); ieee80211_free_node(ni); diff --git a/sys/net80211/ieee80211_power.c b/sys/net80211/ieee80211_power.c index 2d216c2..91668cc 100644 --- a/sys/net80211/ieee80211_power.c +++ b/sys/net80211/ieee80211_power.c @@ -418,6 +418,7 @@ pwrsave_flushq(struct ieee80211_node *ni) struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_psq_head *qhead; + struct ifnet *parent, *ifp; struct mbuf *parent_q = NULL, *ifp_q = NULL; struct mbuf *m; @@ -428,51 +429,59 @@ pwrsave_flushq(struct ieee80211_node *ni) qhead = &psq->psq_head[0]; /* 802.11 frames */ if (qhead->head != NULL) { /* XXX could dispatch through vap and check M_ENCAP */ + parent = vap->iv_ic->ic_ifp; /* XXX need different driver interface */ /* XXX bypasses q max and OACTIVE */ parent_q = qhead->head; qhead->head = qhead->tail = NULL; qhead->len = 0; - } + } else + parent = NULL; qhead = &psq->psq_head[1]; /* 802.3 frames */ if (qhead->head != NULL) { + ifp = vap->iv_ifp; /* XXX need different driver interface */ /* XXX bypasses q max and OACTIVE */ ifp_q = qhead->head; qhead->head = qhead->tail = NULL; qhead->len = 0; - } + } else + ifp = NULL; psq->psq_len = 0; IEEE80211_PSQ_UNLOCK(psq); /* NB: do this outside the psq lock */ /* XXX packets might get reordered if parent is OACTIVE */ /* parent frames, should be encapsulated */ - while (parent_q != NULL) { - m = parent_q; - parent_q = m->m_nextpkt; - m->m_nextpkt = NULL; - /* must be encapsulated */ - KASSERT((m->m_flags & M_ENCAP), - ("%s: parentq with non-M_ENCAP frame!\n", - __func__)); - /* - * For encaped frames, we need to free the node - * reference upon failure. - */ - if (ieee80211_parent_xmitpkt(ic, m) != 0) - ieee80211_free_node(ni); + if (parent != NULL) { + while (parent_q != NULL) { + m = parent_q; + parent_q = m->m_nextpkt; + m->m_nextpkt = NULL; + /* must be encapsulated */ + KASSERT((m->m_flags & M_ENCAP), + ("%s: parentq with non-M_ENCAP frame!\n", + __func__)); + /* + * For encaped frames, we need to free the node + * reference upon failure. + */ + if (ieee80211_parent_xmitpkt(ic, m) != 0) + ieee80211_free_node(ni); + } } /* VAP frames, aren't encapsulated */ - while (ifp_q != NULL) { - m = ifp_q; - ifp_q = m->m_nextpkt; - m->m_nextpkt = NULL; - KASSERT((!(m->m_flags & M_ENCAP)), - ("%s: vapq with M_ENCAP frame!\n", __func__)); - (void) ieee80211_vap_xmitpkt(vap, m); + if (ifp != NULL) { + while (ifp_q != NULL) { + m = ifp_q; + ifp_q = m->m_nextpkt; + m->m_nextpkt = NULL; + KASSERT((!(m->m_flags & M_ENCAP)), + ("%s: vapq with M_ENCAP frame!\n", __func__)); + (void) ieee80211_vap_xmitpkt(vap, m); + } } } diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 7adf044..01c60e1 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -122,23 +122,23 @@ null_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, void ieee80211_proto_attach(struct ieee80211com *ic) { - uint8_t hdrlen; + struct ifnet *ifp = ic->ic_ifp; /* override the 802.3 setting */ - hdrlen = ic->ic_headroom + ifp->if_hdrlen = ic->ic_headroom + sizeof(struct ieee80211_qosframe_addr4) + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN; /* XXX no way to recalculate on ifdetach */ - if (ALIGN(hdrlen) > max_linkhdr) { + if (ALIGN(ifp->if_hdrlen) > max_linkhdr) { /* XXX sanity check... */ - max_linkhdr = ALIGN(hdrlen); + max_linkhdr = ALIGN(ifp->if_hdrlen); max_hdr = max_linkhdr + max_protohdr; max_datalen = MHLEN - max_hdr; } ic->ic_protmode = IEEE80211_PROT_CTSONLY; - TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ic); + TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ifp); TASK_INIT(&ic->ic_mcast_task, 0, update_mcast, ic); TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic); TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic); @@ -188,10 +188,7 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) int i; /* override the 802.3 setting */ - ifp->if_hdrlen = ic->ic_headroom - + sizeof(struct ieee80211_qosframe_addr4) - + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN - + IEEE80211_WEP_EXTIVLEN; + ifp->if_hdrlen = ic->ic_ifp->if_hdrlen; vap->iv_rtsthreshold = IEEE80211_RTS_DEFAULT; vap->iv_fragthreshold = IEEE80211_FRAG_DEFAULT; @@ -1158,9 +1155,9 @@ ieee80211_wme_updateparams(struct ieee80211vap *vap) static void parent_updown(void *arg, int npending) { - struct ieee80211com *ic = arg; + struct ifnet *parent = arg; - ic->ic_parent(ic); + parent->if_ioctl(parent, SIOCSIFFLAGS, NULL); } static void @@ -1227,6 +1224,7 @@ ieee80211_start_locked(struct ieee80211vap *vap) { struct ifnet *ifp = vap->iv_ifp; struct ieee80211com *ic = vap->iv_ic; + struct ifnet *parent = ic->ic_ifp; IEEE80211_LOCK_ASSERT(ic); @@ -1248,10 +1246,12 @@ ieee80211_start_locked(struct ieee80211vap *vap) * We are not running; if this we are the first vap * to be brought up auto-up the parent if necessary. */ - if (ic->ic_nrunning++ == 0) { + if (ic->ic_nrunning++ == 0 && + (parent->if_drv_flags & IFF_DRV_RUNNING) == 0) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, - "%s: up parent %s\n", __func__, ic->ic_name); + "%s: up parent %s\n", __func__, parent->if_xname); + parent->if_flags |= IFF_UP; ieee80211_runtask(ic, &ic->ic_parent_task); return; } @@ -1260,7 +1260,8 @@ ieee80211_start_locked(struct ieee80211vap *vap) * If the parent is up and running, then kick the * 802.11 state machine as appropriate. */ - if (vap->iv_roaming != IEEE80211_ROAMING_MANUAL) { + if ((parent->if_drv_flags & IFF_DRV_RUNNING) && + vap->iv_roaming != IEEE80211_ROAMING_MANUAL) { if (vap->iv_opmode == IEEE80211_M_STA) { #if 0 /* XXX bypasses scan too easily; disable for now */ @@ -1343,6 +1344,7 @@ ieee80211_stop_locked(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; + struct ifnet *parent = ic->ic_ifp; IEEE80211_LOCK_ASSERT(ic); @@ -1352,10 +1354,12 @@ ieee80211_stop_locked(struct ieee80211vap *vap) ieee80211_new_state_locked(vap, IEEE80211_S_INIT, -1); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* mark us stopped */ - if (--ic->ic_nrunning == 0) { + if (--ic->ic_nrunning == 0 && + (parent->if_drv_flags & IFF_DRV_RUNNING)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, - "down parent %s\n", ic->ic_name); + "down parent %s\n", parent->if_xname); + parent->if_flags &= ~IFF_UP; ieee80211_runtask(ic, &ic->ic_parent_task); } } diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index b5918b4..a812393 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -56,8 +56,7 @@ void ieee80211_proto_detach(struct ieee80211com *); void ieee80211_proto_vattach(struct ieee80211vap *); void ieee80211_proto_vdetach(struct ieee80211vap *); -void ieee80211_promisc(struct ieee80211vap *, bool); -void ieee80211_allmulti(struct ieee80211vap *, bool); +void ieee80211_syncifflag_locked(struct ieee80211com *, int flag); void ieee80211_syncflag(struct ieee80211vap *, int flag); void ieee80211_syncflag_ht(struct ieee80211vap *, int flag); void ieee80211_syncflag_ext(struct ieee80211vap *, int flag); diff --git a/sys/net80211/ieee80211_regdomain.c b/sys/net80211/ieee80211_regdomain.c index efbe1a8..9dfef2c 100644 --- a/sys/net80211/ieee80211_regdomain.c +++ b/sys/net80211/ieee80211_regdomain.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/kernel.h> #include <sys/malloc.h> + #include <sys/socket.h> #include <net/if.h> @@ -486,7 +487,7 @@ ieee80211_setregdomain(struct ieee80211vap *vap, memset(&ic->ic_channels[ic->ic_nchans], 0, (IEEE80211_CHAN_MAX - ic->ic_nchans) * sizeof(struct ieee80211_channel)); - ieee80211_chan_init(ic); + ieee80211_media_init(ic); /* * Invalidate channel-related state. diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index 709710c..c0cbb7d 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -1706,6 +1706,26 @@ static const struct ieee80211_scanner adhoc_default = { IEEE80211_SCANNER_ALG(ibss, IEEE80211_M_IBSS, adhoc_default); IEEE80211_SCANNER_ALG(ahdemo, IEEE80211_M_AHDEMO, adhoc_default); +static void +ap_force_promisc(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + + IEEE80211_LOCK(ic); + /* set interface into promiscuous mode */ + ifp->if_flags |= IFF_PROMISC; + ieee80211_runtask(ic, &ic->ic_promisc_task); + IEEE80211_UNLOCK(ic); +} + +static void +ap_reset_promisc(struct ieee80211com *ic) +{ + IEEE80211_LOCK(ic); + ieee80211_syncifflag_locked(ic, IFF_PROMISC); + IEEE80211_UNLOCK(ic); +} + static int ap_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) { @@ -1721,7 +1741,7 @@ ap_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) st->st_scangen++; st->st_newscan = 1; - ieee80211_promisc(vap, true); + ap_force_promisc(vap->iv_ic); return 0; } @@ -1731,7 +1751,7 @@ ap_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) static int ap_cancel(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) { - ieee80211_promisc(vap, false); + ap_reset_promisc(vap->iv_ic); return 0; } @@ -1805,7 +1825,7 @@ ap_end(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) return 0; } } - ieee80211_promisc(vap, false); + ap_reset_promisc(ic); if (ss->ss_flags & (IEEE80211_SCAN_NOPICK | IEEE80211_SCAN_NOJOIN)) { /* * Manual/background scan, don't select+join the diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index a450701..26238b8 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -116,15 +116,16 @@ struct ieee80211_superg; struct ieee80211_frame; struct ieee80211com { + struct ifnet *ic_ifp; /* associated device */ void *ic_softc; /* driver softc */ const char *ic_name; /* usually device name */ ieee80211_com_lock_t ic_comlock; /* state update lock */ ieee80211_tx_lock_t ic_txlock; /* ic/vap TX lock */ - LIST_ENTRY(ieee80211com) ic_next; /* on global list */ TAILQ_HEAD(, ieee80211vap) ic_vaps; /* list of vap instances */ int ic_headroom; /* driver tx headroom needs */ enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */ enum ieee80211_opmode ic_opmode; /* operation mode */ + struct ifmedia ic_media; /* interface media config */ struct callout ic_inact; /* inactivity processing */ struct taskqueue *ic_tq; /* deferred state thread */ struct task ic_parent_task; /* deferred parent processing */ @@ -150,7 +151,6 @@ struct ieee80211com { uint8_t ic_allmulti; /* vap's needing all multicast*/ uint8_t ic_nrunning; /* vap's marked running */ uint8_t ic_curmode; /* current mode */ - uint8_t ic_macaddr[IEEE80211_ADDR_LEN]; uint16_t ic_bintval; /* beacon interval */ uint16_t ic_lintval; /* listen interval */ uint16_t ic_holdover; /* PM hold over duration */ @@ -241,11 +241,6 @@ struct ieee80211com { const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); void (*ic_vap_delete)(struct ieee80211vap *); - /* device specific ioctls */ - int (*ic_ioctl)(struct ieee80211com *, - u_long, void *); - /* start/stop device */ - void (*ic_parent)(struct ieee80211com *); /* operating mode attachment */ ieee80211vap_attach ic_vattach[IEEE80211_OPMODE_MAX]; /* return hardware/radio capabilities */ @@ -259,9 +254,6 @@ struct ieee80211com { int (*ic_set_quiet)(struct ieee80211_node *, u_int8_t *quiet_elm); - /* regular transmit */ - int (*ic_transmit)(struct ieee80211com *, - struct mbuf *); /* send/recv 802.11 management frame */ int (*ic_send_mgmt)(struct ieee80211_node *, int, int); @@ -359,15 +351,14 @@ struct ieee80211vap { TAILQ_ENTRY(ieee80211vap) iv_next; /* list of vap instances */ struct ieee80211com *iv_ic; /* back ptr to common state */ - const uint8_t *iv_myaddr; /* MAC address: ifp or ic */ uint32_t iv_debug; /* debug msg flags */ struct ieee80211_stats iv_stats; /* statistics */ + uint8_t iv_myaddr[IEEE80211_ADDR_LEN]; uint32_t iv_flags; /* state flags */ uint32_t iv_flags_ext; /* extended state flags */ uint32_t iv_flags_ht; /* HT state flags */ uint32_t iv_flags_ven; /* vendor state flags */ - uint32_t iv_ifflags; /* ifnet flags */ uint32_t iv_caps; /* capabilities */ uint32_t iv_htcaps; /* HT capabilities */ uint32_t iv_htextcaps; /* HT extended capabilities */ @@ -690,24 +681,24 @@ MALLOC_DECLARE(M_80211_VAP); "\21AMPDU\22AMSDU\23HT\24SMPS\25RIFS" int ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3); -void ieee80211_ifattach(struct ieee80211com *); +void ieee80211_ifattach(struct ieee80211com *, + const uint8_t macaddr[IEEE80211_ADDR_LEN]); void ieee80211_ifdetach(struct ieee80211com *); int ieee80211_vap_setup(struct ieee80211com *, struct ieee80211vap *, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN]); -int ieee80211_vap_attach(struct ieee80211vap *, - ifm_change_cb_t, ifm_stat_cb_t, + const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t macaddr[IEEE80211_ADDR_LEN]); +int ieee80211_vap_attach(struct ieee80211vap *, + ifm_change_cb_t, ifm_stat_cb_t); void ieee80211_vap_detach(struct ieee80211vap *); const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *); void ieee80211_announce(struct ieee80211com *); void ieee80211_announce_channels(struct ieee80211com *); void ieee80211_drain(struct ieee80211com *); -void ieee80211_chan_init(struct ieee80211com *); +void ieee80211_media_init(struct ieee80211com *); struct ieee80211com *ieee80211_find_vap(const uint8_t mac[IEEE80211_ADDR_LEN]); -struct ieee80211com *ieee80211_find_com(const char *name); int ieee80211_media_change(struct ifnet *); void ieee80211_media_status(struct ifnet *, struct ifmediareq *); int ieee80211_ioctl(struct ifnet *, u_long, caddr_t); |