PERFORCE change 135687 for review
Sam Leffler
sam at FreeBSD.org
Tue Feb 19 00:12:41 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=135687
Change 135687 by sam at sam_ebb on 2008/02/19 00:12:15
first step towards vap support
Affected files ...
.. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#7 edit
.. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#5 edit
.. //depot/projects/vap/sys/dev/ath/if_ath.c#22 edit
.. //depot/projects/vap/sys/dev/ath/if_athrate.h#7 edit
.. //depot/projects/vap/sys/dev/ath/if_athvar.h#12 edit
Differences ...
==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#7 (text+ko) ====
@@ -671,15 +671,15 @@
ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
{
#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
- struct ieee80211com *ic = &sc->sc_ic;
struct ath_node *an = ATH_NODE(ni);
+ const struct ieee80211_txparam *tp = an->an_tp;
struct sample_node *sn = ATH_NODE_SAMPLE(an);
const HAL_RATE_TABLE *rt = sc->sc_currates;
int x, y, srate;
KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
sn->static_rate_ndx = -1;
- if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
+ if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
/*
* A fixed rate is to be used; ic_fixed_rate is the
* IEEE code for this rate (sans basic bit). Convert this
@@ -688,7 +688,7 @@
*/
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
- for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
+ for (; srate >= 0 && RATE(srate) != tp->ucastrate; srate--)
;
/*
* The fixed rate may not be available due to races
@@ -786,18 +786,19 @@
* Reset the rate control state for each 802.11 state transition.
*/
void
-ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
+ath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state state)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
if (state == IEEE80211_S_RUN) {
- if (ic->ic_opmode != IEEE80211_M_STA) {
+ if (vap->iv_opmode != IEEE80211_M_STA) {
/*
* Sync rates for associated stations and neighbors.
*/
ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc);
}
- ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
+ ath_rate_newassoc(sc, ATH_NODE(vap->iv_bss), 1);
}
}
==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#5 (text+ko) ====
==== //depot/projects/vap/sys/dev/ath/if_ath.c#22 (text+ko) ====
@@ -99,49 +99,57 @@
ATH_LED_POLL,
};
+static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
+ const char name[IFNAMSIZ], int unit, int opmode,
+ int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void ath_vap_delete(struct ieee80211vap *);
static void ath_init(void *);
static void ath_stop_locked(struct ifnet *);
static void ath_stop(struct ifnet *);
static void ath_start(struct ifnet *);
static int ath_reset(struct ifnet *);
+static int ath_reset_vap(struct ieee80211vap *);
static int ath_media_change(struct ifnet *);
static void ath_watchdog(struct ifnet *);
static int ath_ioctl(struct ifnet *, u_long, caddr_t);
static void ath_fatal_proc(void *, int);
static void ath_rxorn_proc(void *, int);
+static void ath_bmiss_vap(struct ieee80211vap *);
static void ath_bmiss_proc(void *, int);
-static int ath_key_alloc(struct ieee80211com *,
+static int ath_key_alloc(struct ieee80211vap *,
const struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
-static int ath_key_delete(struct ieee80211com *,
+static int ath_key_delete(struct ieee80211vap *,
const struct ieee80211_key *);
-static int ath_key_set(struct ieee80211com *, const struct ieee80211_key *,
+static int ath_key_set(struct ieee80211vap *, const struct ieee80211_key *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
-static void ath_key_update_begin(struct ieee80211com *);
-static void ath_key_update_end(struct ieee80211com *);
+static void ath_key_update_begin(struct ieee80211vap *);
+static void ath_key_update_end(struct ieee80211vap *);
static void ath_mode_init(struct ath_softc *);
static void ath_setslottime(struct ath_softc *);
static void ath_updateslot(struct ifnet *);
static int ath_beaconq_setup(struct ath_hal *);
static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
-static void ath_beacon_update(struct ieee80211com *, int item);
+static void ath_beacon_update(struct ieee80211vap *, int item);
static void ath_beacon_setup(struct ath_softc *, struct ath_buf *);
static void ath_beacon_proc(void *, int);
+static struct ath_buf *ath_beacon_generate(struct ath_softc *,
+ struct ieee80211vap *);
static void ath_bstuck_proc(void *, int);
+static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
static void ath_beacon_free(struct ath_softc *);
-static void ath_beacon_config(struct ath_softc *);
+static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
static void ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *, ath_bufhead *);
static int ath_desc_alloc(struct ath_softc *);
static void ath_desc_free(struct ath_softc *);
static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *);
static void ath_node_free(struct ieee80211_node *);
-static int8_t ath_node_getrssi(const struct ieee80211_node *);
static void ath_node_getsignal(const struct ieee80211_node *,
int8_t *, int8_t *);
static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
-static void ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni,
+static void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int noise, u_int32_t rstamp);
static void ath_setdefantenna(struct ath_softc *, u_int);
static void ath_rx_proc(void *, int);
@@ -157,6 +165,7 @@
static void ath_tx_proc_q0(void *, int);
static void ath_tx_proc_q0123(void *, int);
static void ath_tx_proc(void *, int);
+static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *);
static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
static void ath_draintxq(struct ath_softc *);
static void ath_stoprecv(struct ath_softc *);
@@ -166,13 +175,12 @@
static void ath_scan_end(struct ieee80211com *);
static void ath_set_channel(struct ieee80211com *);
static void ath_calibrate(void *);
-static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void ath_setup_stationkey(struct ieee80211_node *);
static void ath_newassoc(struct ieee80211_node *, int);
static int ath_getchannels(struct ath_softc *,
HAL_REG_DOMAIN, HAL_CTRY_CODE, HAL_BOOL, HAL_BOOL);
static void ath_led_event(struct ath_softc *, int);
-static void ath_update_txpow(struct ath_softc *);
static int ath_rate_setup(struct ath_softc *, u_int mode);
static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
@@ -378,7 +386,6 @@
goto bad;
}
callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE);
- callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE);
ATH_TXBUF_LOCK_INIT(sc);
@@ -412,8 +419,6 @@
error = EIO;
goto bad2;
}
- /* NB: s/w q, qnum used only by WITNESS */
- ath_txq_init(sc, &sc->sc_mcastq, HAL_NUM_TX_QUEUES+1);
/* NB: insure BK queue is the lowest priority h/w queue */
if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) {
if_printf(ifp, "unable to setup xmit queue for %s traffic!\n",
@@ -497,10 +502,6 @@
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
- ic->ic_reset = ath_reset;
- ic->ic_newassoc = ath_newassoc;
- ic->ic_updateslot = ath_updateslot;
- ic->ic_wme.wme_update = ath_wme_update;
/* XXX not right but it's not used anywhere important */
ic->ic_phytype = IEEE80211_T_OFDM;
ic->ic_opmode = IEEE80211_M_STA;
@@ -603,32 +604,26 @@
/* get mac address from hardware */
ath_hal_getmac(ah, ic->ic_myaddr);
+ /* NB: used to size node table key mapping array */
+ ic->ic_max_keyix = sc->sc_keymax;
/* call MI attach routine. */
ieee80211_ifattach(ic);
sc->sc_opmode = ic->ic_opmode;
+
/* override default methods */
+ ic->ic_newassoc = ath_newassoc;
+ ic->ic_updateslot = ath_updateslot;
+ ic->ic_wme.wme_update = ath_wme_update;
+ ic->ic_vap_create = ath_vap_create;
+ ic->ic_vap_delete = ath_vap_delete;
+ ic->ic_raw_xmit = ath_raw_xmit;
ic->ic_node_alloc = ath_node_alloc;
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = ath_node_free;
- ic->ic_node_getrssi = ath_node_getrssi;
ic->ic_node_getsignal = ath_node_getsignal;
- sc->sc_recv_mgmt = ic->ic_recv_mgmt;
- ic->ic_recv_mgmt = ath_recv_mgmt;
- sc->sc_newstate = ic->ic_newstate;
- ic->ic_newstate = ath_newstate;
ic->ic_scan_start = ath_scan_start;
ic->ic_scan_end = ath_scan_end;
ic->ic_set_channel = ath_set_channel;
- ic->ic_crypto.cs_max_keyix = sc->sc_keymax;
- ic->ic_crypto.cs_key_alloc = ath_key_alloc;
- ic->ic_crypto.cs_key_delete = ath_key_delete;
- ic->ic_crypto.cs_key_set = ath_key_set;
- ic->ic_crypto.cs_key_update_begin = ath_key_update_begin;
- ic->ic_crypto.cs_key_update_end = ath_key_update_end;
- ic->ic_raw_xmit = ath_raw_xmit;
- ic->ic_update_beacon = ath_beacon_update;
- /* complete initialization */
- ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
ath_bpfattach(sc);
/*
@@ -690,6 +685,112 @@
return 0;
}
+static struct ieee80211vap *
+ath_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct ath_vap *avp;
+ struct ieee80211vap *vap;
+
+ if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
+ return NULL;
+ avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (avp == NULL)
+ return NULL;
+ vap = &avp->av_vap;
+ ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+
+ /* h/w crypto support */
+ vap->iv_key_alloc = ath_key_alloc;
+ vap->iv_key_delete = ath_key_delete;
+ vap->iv_key_set = ath_key_set;
+ vap->iv_key_update_begin = ath_key_update_begin;
+ vap->iv_key_update_end = ath_key_update_end;
+
+ /* override various methods */
+ avp->av_recv_mgmt = vap->iv_recv_mgmt;
+ vap->iv_recv_mgmt = ath_recv_mgmt;
+ vap->iv_reset = ath_reset_vap;
+ vap->iv_update_beacon = ath_beacon_update;
+ avp->av_newstate = vap->iv_newstate;
+ vap->iv_newstate = ath_newstate;
+ avp->av_bmiss = vap->iv_bmiss;
+ vap->iv_bmiss = ath_bmiss_vap;
+
+ /* complete setup */
+ ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status);
+
+ ic->ic_opmode = opmode;
+ return vap;
+}
+
+static void
+ath_vap_delete(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ 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);
+
+ 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
+ * the vap state by any frames pending on the tx queues.
+ */
+ ath_hal_intrset(ah, 0); /* disable interrupts */
+ ath_draintxq(sc); /* stop xmit side */
+ ath_stoprecv(sc); /* stop recv side */
+ }
+ /*
+ * Reclaim any pending mcast frames for the vap.
+ */
+ ath_tx_draintxq(sc, &avp->av_mcastq);
+ ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
+
+ /*
+ * Reclaim beacon state. Note this must be done before
+ * the vap instance is reclaimed as we may have a reference
+ * to it in the buffer for the beacon frame.
+ */
+ if (avp->av_bcbuf != NULL) {
+ if (avp->av_bslot != -1) {
+ sc->sc_bslot[avp->av_bslot] = NULL;
+ sc->sc_nbcnvaps--;
+ }
+ ath_beacon_return(sc, avp->av_bcbuf);
+ avp->av_bcbuf = NULL;
+ if (sc->sc_nbcnvaps == 0)
+ sc->sc_stagbeacons = 0;
+ }
+ /*
+ * Update bookkeeping.
+ */
+ if (vap->iv_opmode == IEEE80211_M_STA) {
+ sc->sc_nstavaps--;
+ }
+ ieee80211_vap_detach(vap);
+ free(avp, M_80211_VAP);
+ sc->sc_nvaps--;
+
+ 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).
+ */
+ if (ath_startrecv(sc) != 0)
+ if_printf(ifp, "%s: unable to restart recv logic\n",
+ __func__);
+ if (sc->sc_beacons)
+ ath_beacon_config(sc, NULL);
+ ath_hal_intrset(ah, sc->sc_imask);
+ }
+}
+
void
ath_suspend(struct ath_softc *sc)
{
@@ -864,37 +965,39 @@
}
static void
+ath_bmiss_vap(struct ieee80211vap *vap)
+{
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+ u_int64_t lastrx = sc->sc_lastrx;
+ u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
+ u_int bmisstimeout =
+ vap->iv_bmissthreshold * vap->iv_bss->ni_intval * 1024;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n",
+ __func__, (unsigned long long) tsf,
+ (unsigned long long)(tsf - lastrx),
+ (unsigned long long) lastrx, bmisstimeout);
+ /*
+ * Workaround phantom bmiss interrupts by sanity-checking
+ * the time of our last rx'd frame. If it is within the
+ * beacon miss interval then ignore the interrupt. If it's
+ * truly a bmiss we'll get another interrupt soon and that'll
+ * be dispatched up for processing.
+ */
+ if (tsf - lastrx > bmisstimeout)
+ ATH_VAP(vap)->av_bmiss(vap);
+ else
+ sc->sc_stats.ast_bmiss_phantom++;
+}
+
+static void
ath_bmiss_proc(void *arg, int pending)
{
struct ath_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
- KASSERT(ic->ic_opmode == IEEE80211_M_STA,
- ("unexpect operating mode %u", ic->ic_opmode));
- if (ic->ic_state == IEEE80211_S_RUN) {
- u_int64_t lastrx = sc->sc_lastrx;
- u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
- u_int bmisstimeout =
- ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024;
-
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n",
- __func__, (unsigned long long) tsf,
- (unsigned long long)(tsf - lastrx),
- (unsigned long long) lastrx, bmisstimeout);
- /*
- * Workaround phantom bmiss interrupts by sanity-checking
- * the time of our last rx'd frame. If it is within the
- * beacon miss interval then ignore the interrupt. If it's
- * truly a bmiss we'll get another interrupt soon and that'll
- * be dispatched up for processing.
- */
- if (tsf - lastrx > bmisstimeout)
- ieee80211_beacon_miss(ic);
- else
- sc->sc_stats.ast_bmiss_phantom++;
- }
+ ieee80211_beacon_miss(&sc->sc_ic);
}
/*
@@ -971,13 +1074,9 @@
status);
goto done;
}
+ ath_chan_change(sc, ic->ic_curchan);
/*
- * This is needed only to setup initial state
- * but it's best done after a reset.
- */
- ath_update_txpow(sc);
- /*
* Likewise this is set during reset so update
* state cached in the driver.
*/
@@ -1009,27 +1108,16 @@
*/
if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
sc->sc_imask |= HAL_INT_MIB;
- ath_hal_intrset(ah, sc->sc_imask);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
- ic->ic_state = IEEE80211_S_INIT;
+ ath_hal_intrset(ah, sc->sc_imask);
- /*
- * The hardware should be ready to go now so it's safe
- * to kick the 802.11 state machine as it's likely to
- * immediately call back to us to send mgmt frames.
- */
- ath_chan_change(sc, ic->ic_curchan);
#ifdef ATH_TX99_DIAG
if (sc->sc_tx99 != NULL)
sc->sc_tx99->start(sc->sc_tx99);
else
#endif
- if (ic->ic_opmode != IEEE80211_M_MONITOR) {
- if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- } else
- ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ ieee80211_start_all(ic); /* start all vap's */
done:
ATH_UNLOCK(sc);
}
@@ -1038,7 +1126,6 @@
ath_stop_locked(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
struct ath_hal *ah = sc->sc_ah;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n",
@@ -1065,7 +1152,6 @@
if (sc->sc_tx99 != NULL)
sc->sc_tx99->stop(sc->sc_tx99);
#endif
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
ifp->if_timer = 0;
if (!sc->sc_invalid) {
@@ -1083,8 +1169,7 @@
ath_hal_phydisable(ah);
} else
sc->sc_rxlink = NULL;
- IFQ_DRV_PURGE(&ifp->if_snd);
- ath_beacon_free(sc);
+ ath_beacon_free(sc); /* XXX not needed */
}
}
@@ -1138,7 +1223,6 @@
if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status))
if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
__func__, status);
- ath_update_txpow(sc); /* update tx power state */
sc->sc_diversity = ath_hal_getdiversity(ah);
sc->sc_calinterval = 1;
sc->sc_caltries = 0;
@@ -1150,14 +1234,20 @@
* might change as a result.
*/
ath_chan_change(sc, ic->ic_curchan);
- if (ic->ic_state == IEEE80211_S_RUN)
- ath_beacon_config(sc); /* restart beacons */
+ if (sc->sc_beacons)
+ ath_beacon_config(sc, NULL); /* restart beacons */
ath_hal_intrset(ah, sc->sc_imask);
ath_start(ifp); /* restart xmit */
return 0;
}
+static int
+ath_reset_vap(struct ieee80211vap *vap)
+{
+ return ath_reset(vap->iv_ic->ic_ifp);
+}
+
static int
ath_ff_always(struct ath_txq *txq, struct ath_buf *bf)
{
@@ -1210,7 +1300,7 @@
sc->sc_stats.ast_ff_flush++;
/* encap and xmit */
- bf->bf_m = ieee80211_encap(&sc->sc_ic, bf->bf_m, ni);
+ bf->bf_m = ieee80211_encap(ni, bf->bf_m);
if (bf->bf_m == NULL) {
DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
"%s: discard, encapsulation failure\n",
@@ -1330,7 +1420,6 @@
ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni)
{
- struct ieee80211com *ic = ni->ni_ic;
struct ath_node *an = ATH_NODE(ni);
struct ath_buf *bfstaged;
int ff_flush, pri;
@@ -1423,7 +1512,7 @@
ether_sprintf(an->an_node.ni_macaddr));
/* encap and xmit */
- bfstaged->bf_m = ieee80211_encap(ic, bfstaged->bf_m, ni);
+ bfstaged->bf_m = ieee80211_encap(ni, bfstaged->bf_m);
if (bfstaged->bf_m == NULL) {
DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
"%s: discard, encap failure\n", __func__);
@@ -1525,13 +1614,10 @@
ath_start(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ath_hal *ah = sc->sc_ah;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ath_buf *bf;
struct mbuf *m, *next;
- struct ieee80211_frame *wh;
- struct ether_header *eh;
struct ath_txq *txq;
ath_bufhead frags;
int pri;
@@ -1539,6 +1625,9 @@
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
return;
for (;;) {
+ IFQ_POLL(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
/*
* Grab a TX buffer and associated resources.
*/
@@ -1550,158 +1639,70 @@
if (bf == NULL) {
DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n",
__func__);
+ /* XXX tail drop */
sc->sc_stats.ast_tx_qstop++;
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
break;
}
- /*
- * Poll the management queue for frames; they
- * have priority over normal data frames.
- */
- IF_DEQUEUE(&ic->ic_mgtq, m);
+
+ STAILQ_INIT(&frags);
+ IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL) {
/*
- * No data frames go out unless we're associated.
+ * The q was emptied while we blocked,
+ * this can happen when we're preempted.
*/
- if (ic->ic_state != IEEE80211_S_RUN) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: discard data packet, state %s\n",
- __func__,
- ieee80211_state_name[ic->ic_state]);
- sc->sc_stats.ast_tx_discard++;
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
- break;
- }
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */
- if (m == NULL) {
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
- break;
- }
+ ni = NULL;
+ goto reclaim;
+ }
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ pri = M_WME_GETAC(m);
+ txq = sc->sc_ac2q[pri];
+ if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
/*
- * Cancel any background scan.
+ * Check queue length; if too deep drop this
+ * frame (tail drop considered good).
*/
- if (ic->ic_flags & IEEE80211_F_SCAN)
- ieee80211_cancel_scan(ic);
-
- STAILQ_INIT(&frags);
- /*
- * Find the node for the destination so we can do
- * things like power save and fast frames aggregation.
- */
- if (m->m_len < sizeof(struct ether_header) &&
- (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
- ic->ic_stats.is_tx_nobuf++; /* XXX */
- ni = NULL;
- goto bad;
- }
- eh = mtod(m, struct ether_header *);
- ni = ieee80211_find_txnode(ic, eh->ether_dhost);
- if (ni == NULL) {
- /* NB: ieee80211_find_txnode does stat+msg */
+ if (txq->axq_depth >= sc->sc_fftxqmax) {
+ DPRINTF(sc, ATH_DEBUG_FF,
+ "[%s] tail drop on q %u depth %u\n",
+ ether_sprintf(ni->ni_macaddr),
+ txq->axq_qnum, txq->axq_depth);
+ sc->sc_stats.ast_tx_qfull++;
m_freem(m);
- goto bad;
- }
- if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
- (m->m_flags & M_PWR_SAV) == 0) {
- /*
- * Station in power save mode; pass the frame
- * to the 802.11 layer and continue. We'll get
- * the frame back when the time is right.
- */
- ieee80211_pwrsave(ni, m);
goto reclaim;
}
- /* calculate priority so we can find the tx queue */
- if (ieee80211_classify(ic, m, ni)) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: discard, classification failure\n",
- __func__);
- m_freem(m);
- goto bad;
- }
- pri = M_WME_GETAC(m);
- txq = sc->sc_ac2q[pri];
- if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
- /*
- * Check queue length; if too deep drop this
- * frame (tail drop considered good).
- */
- if (txq->axq_depth >= sc->sc_fftxqmax) {
- DPRINTF(sc, ATH_DEBUG_FF,
- "[%s] tail drop on q %u depth %u\n",
- ether_sprintf(ni->ni_macaddr),
- txq->axq_qnum, txq->axq_depth);
- sc->sc_stats.ast_tx_qfull++;
- m_freem(m);
- goto reclaim;
- }
- m = ath_ff_check(sc, txq, bf, m, ni);
- if (m == NULL) {
- /* NB: ni ref & bf held on stageq */
- continue;
- }
- }
- ifp->if_opackets++;
- BPF_MTAP(ifp, m);
- /*
- * Encapsulate the packet in prep for transmission.
- */
- m = ieee80211_encap(ic, m, ni);
+ m = ath_ff_check(sc, txq, bf, m, ni);
if (m == NULL) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: encapsulation failure\n",
- __func__);
- sc->sc_stats.ast_tx_encap++;
- goto bad;
+ /* NB: ni ref & bf held on stageq */
+ continue;
}
- /*
- * 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 ((m->m_flags & M_FRAG) &&
- !ath_txfrag_setup(sc, &frags, m, ni)) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: out of txfrag buffers\n", __func__);
- ic->ic_stats.is_tx_nobuf++; /* XXX */
- ath_freetx(m);
- goto bad;
- }
- } else {
- /*
- * Hack! The referenced node pointer is in the
- * rcvif field of the packet header. This is
- * placed there by ieee80211_mgmt_output because
- * we need to hold the reference with the frame
- * and there's no other way (other than packet
- * tags which we consider too expensive to use)
- * to pass it along.
- */
- ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
- m->m_pkthdr.rcvif = NULL;
-
- wh = mtod(m, struct ieee80211_frame *);
- if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
- IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
- /* fill time stamp */
- u_int64_t tsf;
- u_int32_t *tstamp;
-
- tsf = ath_hal_gettsf64(ah);
- /* XXX: adjust 100us delay to xmit */
- tsf += 100;
- tstamp = (u_int32_t *)&wh[1];
- tstamp[0] = htole32(tsf & 0xffffffff);
- tstamp[1] = htole32(tsf >> 32);
- }
- sc->sc_stats.ast_tx_mgmt++;
+ }
+ ifp->if_opackets++;
+ /*
+ * Encapsulate the packet in prep for transmission.
+ */
+ m = ieee80211_encap(ni, m);
+ if (m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: encapsulation failure\n", __func__);
+ sc->sc_stats.ast_tx_encap++;
+ goto bad;
+ }
+ /*
+ * 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 ((m->m_flags & M_FRAG) &&
+ !ath_txfrag_setup(sc, &frags, m, ni)) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: out of txfrag buffers\n", __func__);
+ ic->ic_stats.is_tx_nobuf++; /* XXX */
+ ath_freetx(m);
+ goto bad;
}
-
nextfrag:
/*
* Pass the frame to the h/w for transmission.
@@ -1735,11 +1736,11 @@
* Beware of state changing between frags.
* XXX check sta power-save state?
*/
- if (ic->ic_state != IEEE80211_S_RUN) {
+ if (ni->ni_vap->iv_state != IEEE80211_S_RUN) {
DPRINTF(sc, ATH_DEBUG_XMIT,
"%s: flush fragmented packet, state %s\n",
__func__,
- ieee80211_state_name[ic->ic_state]);
+ ieee80211_state_name[ni->ni_vap->iv_state]);
ath_freetx(next);
goto reclaim;
}
@@ -1751,7 +1752,6 @@
}
ifp->if_timer = 5;
- ic->ic_lastdata = ticks;
#if 0
/*
* Flush stale frames from the fast-frame staging queue.
@@ -1765,30 +1765,9 @@
static int
ath_media_change(struct ifnet *ifp)
{
-#define IS_UP(ifp) \
- ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
- int error;
-
- error = ieee80211_media_change(ifp);
- if (error == ENETRESET) {
- struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
-
- if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
- /*
- * Adhoc demo mode is just ibss mode w/o beacons
- * (mostly). The hal knows nothing about it;
- * tell it we're operating in ibss mode.
- */
- sc->sc_opmode = HAL_M_IBSS;
- } else
- sc->sc_opmode = ic->ic_opmode;
- if (IS_UP(ifp))
- ath_init(sc); /* XXX lose error */
- error = 0;
- }
- return error;
-#undef IS_UP
+ int error = ieee80211_media_change(ifp);
+ /* NB: only the fixed rate can change and that doesn't need a reset */
+ return (error == ENETRESET ? 0 : error);
}
#ifdef ATH_DEBUG
@@ -2091,10 +2070,10 @@
* 64 entries.
*/
static int
-ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
/*
* Group key allocation must be handled specially for
@@ -2108,8 +2087,8 @@
* multi-station operation.
*/
if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) {
- if (!(&ic->ic_nw_keys[0] <= k &&
- k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
+ if (!(&vap->iv_nw_keys[0] <= k &&
+ k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
/* should not happen */
DPRINTF(sc, ATH_DEBUG_KEYCACHE,
"%s: bogus group key\n", __func__);
@@ -2119,7 +2098,7 @@
* XXX we pre-allocate the global keys so
* have no way to check if they've already been allocated.
*/
- *keyix = *rxkeyix = k - ic->ic_nw_keys;
+ *keyix = *rxkeyix = k - vap->iv_nw_keys;
return 1;
}
@@ -2148,9 +2127,9 @@
* Delete an entry in the key cache allocated by ath_key_alloc.
*/
static int
-ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
+ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
{
- struct ath_softc *sc = ic->ic_ifp->if_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;
@@ -2188,12 +2167,12 @@
* slot(s) must already have been allocated by ath_key_alloc.
*/
static int
-ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
+ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
const u_int8_t mac[IEEE80211_ADDR_LEN])
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
- return ath_keyset(sc, k, mac, ic->ic_bss);
+ return ath_keyset(sc, k, mac, vap->iv_bss);
}
/*
@@ -2203,9 +2182,9 @@
* uses that originate in the driver.
*/
static void
-ath_key_update_begin(struct ieee80211com *ic)
+ath_key_update_begin(struct ieee80211vap *vap)
{
- struct ifnet *ifp = ic->ic_ifp;
+ struct ifnet *ifp = vap->iv_ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
@@ -2216,9 +2195,9 @@
}
static void
-ath_key_update_end(struct ieee80211com *ic)
+ath_key_update_end(struct ieee80211vap *vap)
{
- struct ifnet *ifp = ic->ic_ifp;
+ struct ifnet *ifp = vap->iv_ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
@@ -2233,8 +2212,6 @@
* operating mode and state:
*
* o always accept unicast, broadcast, and multicast traffic
- * o maintain current state of phy error reception (the hal
- * may enable phy error frames for noise immunity work)
* o probe request frames are accepted only when operating in
* hostap, adhoc, or monitor modes
* o enable promiscuous mode according to the interface state
@@ -2246,31 +2223,68 @@
* - when scanning
* o accept control frames:
* - when in monitor mode
+ * XXX BAR frames for 11n
*/
static u_int32_t
ath_calcrxfilter(struct ath_softc *sc)
{
-#define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)
struct ieee80211com *ic = &sc->sc_ic;
- struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
u_int32_t rfilt;
- rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE)
- | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
+ rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
if (ic->ic_opmode != IEEE80211_M_STA)
rfilt |= HAL_RX_FILTER_PROBEREQ;
if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
(ifp->if_flags & IFF_PROMISC))
rfilt |= HAL_RX_FILTER_PROM;
if (ic->ic_opmode == IEEE80211_M_STA ||
- ic->ic_opmode == IEEE80211_M_IBSS ||
+ sc->sc_opmode == HAL_M_IBSS ||
sc->sc_scanning)
rfilt |= HAL_RX_FILTER_BEACON;
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rfilt |= HAL_RX_FILTER_CONTROL;
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ !sc->sc_needmib && !sc->sc_scanning)
+ rfilt |= HAL_RX_FILTER_PHYERR;
return rfilt;
-#undef RX_FILTER_PRESERVE
+}
+
+/*
+ * Merge multicast address from all vap's to form the hardware
+ * filter. Ideally we should only inspect our own list and the
+ * 802.11 layer would merge for us but that's bit difficult so
+ * for now we put the onus on the driver.
+ */
+static void
+ath_merge_mcast(struct ath_softc *sc, u_int32_t mfilt[2])
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap;
+
+ mfilt[0] = mfilt[1] = 0;
+ /* XXX locking */
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+ struct ifnet *ifp = vap->iv_ifp;
+ struct ifmultiaddr *ifma;
+
+ IF_ADDR_LOCK(ifp);
+ 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_ADDR_UNLOCK(ifp);
+ }
}
static void
@@ -2279,9 +2293,7 @@
struct ieee80211com *ic = &sc->sc_ic;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list