diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2012-08-25 12:14:32 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2012-08-25 12:14:32 +0000 |
commit | f25d3c072ab38c54fdae4ec4d91b08f5e209bc72 (patch) | |
tree | a0edea35093f3140a9c482c9a6b469298fd9c175 /sys/dev | |
parent | 7d734daf7474e6afa9ef273b4577804ab444a1b7 (diff) |
Add support for power saving in Host AP mode.
ok stsp@, deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/ar5008.c | 31 | ||||
-rw-r--r-- | sys/dev/ic/ar9003.c | 31 | ||||
-rw-r--r-- | sys/dev/ic/athn.c | 13 | ||||
-rw-r--r-- | sys/dev/ic/athnvar.h | 3 |
4 files changed, 73 insertions, 5 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c index 6a884fab51d..83fb33e18e3 100644 --- a/sys/dev/ic/ar5008.c +++ b/sys/dev/ic/ar5008.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar5008.c,v 1.20 2011/06/19 00:27:34 matthew Exp $ */ +/* $OpenBSD: ar5008.c,v 1.21 2012/08/25 12:14:31 kettenis Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -1053,6 +1053,8 @@ int ar5008_swba_intr(struct athn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + struct ieee80211_node *ni = ic->ic_bss; struct athn_tx_buf *bf = sc->bcnbuf; struct ieee80211_frame *wh; struct ar_tx_desc *ds; @@ -1060,6 +1062,11 @@ ar5008_swba_intr(struct athn_softc *sc) uint8_t ridx, hwrate; int error, totlen; + if (ic->ic_tim_mcast_pending && + IF_IS_EMPTY(&ni->ni_savedq) && + SIMPLEQ_EMPTY(&sc->txq[ATHN_QID_CAB].head)) + ic->ic_tim_mcast_pending = 0; + if (ic->ic_dtim_count == 0) ic->ic_dtim_count = ic->ic_dtim_period - 1; else @@ -1133,6 +1140,26 @@ ar5008_swba_intr(struct athn_softc *sc) AR_WRITE(sc, AR_QTXDP(ATHN_QID_BEACON), bf->bf_daddr); + for(;;) { + if (SIMPLEQ_EMPTY(&sc->txbufs)) + break; + + IF_DEQUEUE(&ni->ni_savedq, m); + if (m == NULL) + break; + if (!IF_IS_EMPTY(&ni->ni_savedq)) { + /* more queued frames, set the more data bit */ + wh = mtod(m, struct ieee80211_frame *); + wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; + } + + if (sc->ops.tx(sc, m, ni, ATHN_TXFLAG_CAB) != 0) { + ieee80211_release_node(ic, ni); + ifp->if_oerrors++; + break; + } + } + /* Kick Tx. */ AR_WRITE(sc, AR_Q_TXE, 1 << ATHN_QID_BEACON); AR_WRITE_BARRIER(sc); @@ -1285,6 +1312,8 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, qid = athn_ac2qid[ieee80211_up_to_ac(ic, tid)]; } else if (type == AR_FRAME_TYPE_PSPOLL) { qid = ATHN_QID_PSPOLL; + } else if (txflags & ATHN_TXFLAG_CAB) { + qid = ATHN_QID_CAB; } else qid = ATHN_QID_AC_BE; txq = &sc->txq[qid]; diff --git a/sys/dev/ic/ar9003.c b/sys/dev/ic/ar9003.c index 9d94b427d16..ff547f4ab16 100644 --- a/sys/dev/ic/ar9003.c +++ b/sys/dev/ic/ar9003.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar9003.c,v 1.22 2011/01/01 13:44:42 damien Exp $ */ +/* $OpenBSD: ar9003.c,v 1.23 2012/08/25 12:14:31 kettenis Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -1183,6 +1183,8 @@ int ar9003_swba_intr(struct athn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + struct ieee80211_node *ni = ic->ic_bss; struct athn_tx_buf *bf = sc->bcnbuf; struct ieee80211_frame *wh; struct ar_tx_desc *ds; @@ -1191,6 +1193,11 @@ ar9003_swba_intr(struct athn_softc *sc) uint8_t ridx, hwrate; int error, totlen; + if (ic->ic_tim_mcast_pending && + IF_IS_EMPTY(&ni->ni_savedq) && + SIMPLEQ_EMPTY(&sc->txq[ATHN_QID_CAB].head)) + ic->ic_tim_mcast_pending = 0; + if (ic->ic_dtim_count == 0) ic->ic_dtim_count = ic->ic_dtim_period - 1; else @@ -1276,6 +1283,26 @@ ar9003_swba_intr(struct athn_softc *sc) AR_WRITE(sc, AR_QTXDP(ATHN_QID_BEACON), bf->bf_daddr); + for(;;) { + if (SIMPLEQ_EMPTY(&sc->txbufs)) + break; + + IF_DEQUEUE(&ni->ni_savedq, m); + if (m == NULL) + break; + if (!IF_IS_EMPTY(&ni->ni_savedq)) { + /* more queued frames, set the more data bit */ + wh = mtod(m, struct ieee80211_frame *); + wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; + } + + if (sc->ops.tx(sc, m, ni, ATHN_TXFLAG_CAB) != 0) { + ieee80211_release_node(ic, ni); + ifp->if_oerrors++; + break; + } + } + /* Kick Tx. */ AR_WRITE(sc, AR_Q_TXE, 1 << ATHN_QID_BEACON); AR_WRITE_BARRIER(sc); @@ -1425,6 +1452,8 @@ ar9003_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, qid = athn_ac2qid[ieee80211_up_to_ac(ic, tid)]; } else if (type == AR_FRAME_TYPE_PSPOLL) { qid = ATHN_QID_PSPOLL; + } else if (txflags & ATHN_TXFLAG_CAB) { + qid = ATHN_QID_CAB; } else qid = ATHN_QID_AC_BE; txq = &sc->txq[qid]; diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c index d58dc53b37f..b985a0915be 100644 --- a/sys/dev/ic/athn.c +++ b/sys/dev/ic/athn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: athn.c,v 1.72 2012/06/10 21:23:36 kettenis Exp $ */ +/* $OpenBSD: athn.c,v 1.73 2012/08/25 12:14:31 kettenis Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -282,7 +282,8 @@ athn_attach(struct athn_softc *sc) IEEE80211_C_WEP | /* WEP. */ IEEE80211_C_RSN | /* WPA/RSN. */ #ifndef IEEE80211_STA_ONLY - IEEE80211_C_HOSTAP | /* Host Ap mode supported. */ + IEEE80211_C_HOSTAP | /* Host AP mode supported. */ + IEEE80211_C_APPMGT | /* Host AP power saving supported. */ #endif IEEE80211_C_MONITOR | /* Monitor mode supported. */ IEEE80211_C_SHSLOT | /* Short slot time supported. */ @@ -2546,6 +2547,14 @@ athn_start(struct ifnet *ifp) if (ic->ic_state != IEEE80211_S_RUN) break; + IF_DEQUEUE(&ic->ic_pwrsaveq, m); + if (m != NULL) { + ni = (void *)m->m_pkthdr.rcvif; + goto sendit; + } + if (ic->ic_state != IEEE80211_S_RUN) + break; + /* Encapsulate and send data frames. */ IFQ_DEQUEUE(&ifp->if_snd, m); if (m == NULL) diff --git a/sys/dev/ic/athnvar.h b/sys/dev/ic/athnvar.h index b21a332e29d..b9548738b92 100644 --- a/sys/dev/ic/athnvar.h +++ b/sys/dev/ic/athnvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: athnvar.h,v 1.31 2012/06/10 21:23:36 kettenis Exp $ */ +/* $OpenBSD: athnvar.h,v 1.32 2012/08/25 12:14:31 kettenis Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -83,6 +83,7 @@ struct athn_tx_buf { struct ieee80211_node *bf_ni; int bf_txflags; #define ATHN_TXFLAG_PAPRD (1 << 0) +#define ATHN_TXFLAG_CAB (1 << 1) }; struct athn_txq { |