When dispatching frames saved on the power save queue to a

station exiting power save mode prepend them to the driver's
send q instead of appending them.  This insures the packets
are not misordered wrt any packets already q'd for the station.

This corrects a problem noticed when using a VoIP phone talking
to an ath card in ap mode; the misordered packets caused noise.

Submitted by:	"J.R. Oldroyd" <jr@opal.com>
MFC after:	2 weeks
This commit is contained in:
sam 2007-03-07 04:42:22 +00:00
parent 24d9d9d380
commit 519f61f995
2 changed files with 38 additions and 13 deletions

View File

@ -115,6 +115,21 @@ typedef struct mtx ieee80211_scan_lock_t;
(_qlen) = ++(_ni)->ni_savedq.ifq_len; \
} while (0)
#ifndef IF_PREPEND_LIST
#define _IF_PREPEND_LIST(ifq, mhead, mtail, mcount) do { \
(mtail)->m_nextpkt = (ifq)->ifq_head; \
if ((ifq)->ifq_tail == NULL) \
(ifq)->ifq_tail = (mtail); \
(ifq)->ifq_head = (mhead); \
(ifq)->ifq_len += (mcount); \
} while (0)
#define IF_PREPEND_LIST(ifq, mhead, mtail, mcount) do { \
IF_LOCK(ifq); \
_IF_PREPEND_LIST(ifq, mhead, mtail, mcount); \
IF_UNLOCK(ifq); \
} while (0)
#endif /* IF_PREPEND_LIST */
/*
* 802.1x MAC ACL database locking definitions.
*/

View File

@ -2633,7 +2633,8 @@ static void
ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable)
{
struct ieee80211com *ic = ni->ni_ic;
struct mbuf *m;
struct mbuf *m, *mhead, *mtail;
int mcount;
if (enable) {
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0)
@ -2664,23 +2665,32 @@ ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable)
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
"[%s] flush ps queue, %u packets queued\n",
ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_SAVEQ_QLEN(ni));
/*
* Unload the frames from the ps q but don't send them
* to the driver yet. We do this in two stages to minimize
* locking but also because there's no easy way to preserve
* ordering given the existing ifnet access mechanisms.
* XXX could be optimized
*/
IEEE80211_NODE_SAVEQ_LOCK(ni);
mcount = IEEE80211_NODE_SAVEQ_QLEN(ni);
mhead = mtail = NULL;
for (;;) {
int qlen;
IEEE80211_NODE_SAVEQ_DEQUEUE(ni, m, qlen);
_IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m);
if (m == NULL)
break;
/*
* If this is the last packet, turn off the TIM bit.
* If there are more packets, set the more packets bit
* in the mbuf so ieee80211_encap will mark the 802.11
* head to indicate more data frames will follow.
*/
if (qlen != 0)
m->m_flags |= M_MORE_DATA;
if (mhead == NULL) {
mhead = m;
m->m_nextpkt = NULL;
} else
mtail->m_nextpkt = m;
mtail = m;
}
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
if (mhead != NULL) {
/* XXX need different driver interface */
/* XXX bypasses q max */
IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
IF_PREPEND_LIST(&ic->ic_ifp->if_snd, mhead, mtail, mcount);
}
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ni, 0);