Ensure that single-frame aggregate session frames are retransmitted

with the correct configuration.

Occasionally an aggregate TX would fail and the first frame would be
retransmitted as a non-AMPDU frame.  Since bfs_aggr=1 and bfs_nframes > 1
(from the previous AMPDU attempt), the aggr completion function would be
called and be very confused about what's going on.

Noticed by:	Kim <w8hdkim@gmail.com>
PR:		kern/171394
This commit is contained in:
Adrian Chadd 2012-09-07 00:24:27 +00:00
parent 5ac7ffcc38
commit 2a9f83af64
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=240180

View File

@ -2528,6 +2528,25 @@ ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an,
return;
}
/*
* This is a temporary check and should be removed once
* all the relevant code paths have been fixed.
*
* During aggregate retries, it's possible that the head
* frame will fail (which has the bfs_aggr and bfs_nframes
* fields set for said aggregate) and will be retried as
* a single frame. In this instance, the values should
* be reset or the completion code will get upset with you.
*/
if (bf->bf_state.bfs_aggr != 0 || bf->bf_state.bfs_nframes > 1) {
device_printf(sc->sc_dev, "%s: bfs_aggr=%d, bfs_nframes=%d\n",
__func__,
bf->bf_state.bfs_aggr,
bf->bf_state.bfs_nframes);
bf->bf_state.bfs_aggr = 0;
bf->bf_state.bfs_nframes = 1;
}
/* Direct dispatch to hardware */
ath_tx_do_ratelookup(sc, bf);
ath_tx_calc_duration(sc, bf);
@ -2624,6 +2643,16 @@ ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_txq *txq,
if (txq->axq_depth < sc->sc_hwq_limit) {
bf = TAILQ_FIRST(&atid->axq_q);
ATH_TXQ_REMOVE(atid, bf, bf_list);
/*
* Ensure it's definitely treated as a non-AMPDU
* frame - this information may have been left
* over from a previous attempt.
*/
bf->bf_state.bfs_aggr = 0;
bf->bf_state.bfs_nframes = 1;
/* Queue to the hardware */
ath_tx_xmit_aggr(sc, an, txq, bf);
DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: xmit_aggr\n",
@ -4018,7 +4047,23 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
"%s: non-baw packet\n",
__func__);
ATH_TXQ_REMOVE(tid, bf, bf_list);
if (bf->bf_state.bfs_nframes > 1)
device_printf(sc->sc_dev,
"%s: aggr=%d, nframes=%d\n",
__func__,
bf->bf_state.bfs_aggr,
bf->bf_state.bfs_nframes);
/*
* This shouldn't happen - such frames shouldn't
* ever have been queued as an aggregate in the
* first place. However, make sure the fields
* are correctly setup just to be totally sure.
*/
bf->bf_state.bfs_aggr = 0;
bf->bf_state.bfs_nframes = 1;
ath_tx_do_ratelookup(sc, bf);
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);