/* * Age frames on the power save queue. The aging interval is * 4 times the listen interval specified by the station. This * number is factored into the age calculations when the frame * is placed on the queue. We store ages as time differences * so we can check and/or adjust only the head of the list. * If a frame's age exceeds the threshold then discard it. * The number of frames discarded is returned so the caller * can check if it needs to adjust the tim. */ int ieee80211_node_saveq_age(struct ieee80211_node *ni) { int discard = 0; struct node_powersave_queue *dataq,*mgtq; struct ieee80211vap *vap=ni->ni_vap; dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); /* XXX racey but good 'nuf? */ if ((IEEE80211_NODE_SAVEQ_QLEN(dataq) != 0) || (IEEE80211_NODE_SAVEQ_QLEN(mgtq) != 0)) { wbuf_t wbuf; IEEE80211_NODE_SAVEQ_LOCK(dataq); while (IEEE80211_NODE_SAVEQ_POLL(dataq, wbuf) != NULL && wbuf_get_age(wbuf) < IEEE80211_INACT_WAIT) { struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "discard frame, age %u \n", wbuf_get_age(wbuf)); IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); ieee80211_release_wbuf(ni,wbuf, &ts); discard++; } if (wbuf != NULL) wbuf_set_age(wbuf, wbuf_get_age(wbuf) - IEEE80211_INACT_WAIT); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); while (IEEE80211_NODE_SAVEQ_POLL(mgtq, wbuf) != NULL && wbuf_get_age(wbuf) < IEEE80211_INACT_WAIT) { struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "discard mgt frame, age %u \n", wbuf_get_age(wbuf)); IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); ieee80211_release_wbuf(ni,wbuf, &ts); discard++; } if (wbuf != NULL) wbuf_set_age(wbuf, wbuf_get_age(wbuf) - IEEE80211_INACT_WAIT); IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "discard %u frames for age \n", discard); IEEE80211_NODE_STAT_ADD(ni, ps_discard, discard); } if ((IEEE80211_NODE_SAVEQ_QLEN(dataq) == 0) && (IEEE80211_NODE_SAVEQ_QLEN(mgtq) == 0)) { if (vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 0); } return discard; }
/* * Age frames on the power save queue. The aging interval is * 4 times the listen interval specified by the station. This * number is factored into the age calculations when the frame * is placed on the queue. We store ages as time differences * so we can check and/or adjust only the head of the list. * If a frame's age exceeds the threshold then discard it. * The number of frames discarded is returned so the caller * can check if it needs to adjust the tim. */ int ath_node_pwrsaveq_age(ath_node_t node) { struct ath_node *an = ATH_NODE(node); struct ath_softc *sc = an->an_sc; int discard = 0; struct ath_node_pwrsaveq *dataq,*mgtq; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); if ((ATH_NODE_PWRSAVEQ_QLEN(dataq) != 0) || (ATH_NODE_PWRSAVEQ_QLEN(mgtq) != 0)) { ath_wbuf_t athwbuf; for (;;) { ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_POLL(dataq, athwbuf); if((athwbuf == NULL) || (wbuf_get_age(athwbuf->wbuf) >= ATH_NODE_INACT_WAIT)) { if (athwbuf != NULL) wbuf_set_age(athwbuf->wbuf, wbuf_get_age(athwbuf->wbuf) - ATH_NODE_INACT_WAIT); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); break; } DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "discard data frame, age %u \n", wbuf_get_age(athwbuf->wbuf)); ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); discard++; } for (;;) { ATH_NODE_PWRSAVEQ_LOCK(mgtq); ATH_NODE_PWRSAVEQ_POLL(mgtq, athwbuf); if((athwbuf == NULL) || (wbuf_get_age(athwbuf->wbuf) >= ATH_NODE_INACT_WAIT)) { if (athwbuf != NULL) wbuf_set_age(athwbuf->wbuf, wbuf_get_age(athwbuf->wbuf) - ATH_NODE_INACT_WAIT); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); break; } DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "discard mgt frame, age %u \n", wbuf_get_age(athwbuf->wbuf)); ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); discard++; } DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "discard %u frames for age \n", discard); } return discard; }
/* * Age frames on the power save queue. The aging interval is * 4 times the listen interval specified by the station. This * number is factored into the age calculations when the frame * is placed on the queue. We store ages as time differences * so we can check and/or adjust only the head of the list. * If a frame's age exceeds the threshold then discard it. * The number of frames discarded is returned so the caller * can check if it needs to adjust the tim. */ int ieee80211_node_saveq_age(struct ieee80211_node *ni) { int discard = 0; struct node_powersave_queue *dataq,*mgtq; struct ieee80211vap *vap=ni->ni_vap; #if LMAC_SUPPORT_POWERSAVE_QUEUE struct ieee80211com *ic = ni->ni_ic; ic->ic_node_pwrsaveq_age(ic, ni); if (ic->ic_get_lmac_pwrsaveq_len(ic, ni, 0) == 0 && vap->iv_set_tim != NULL) { vap->iv_set_tim(ni, 0, false); } return 0; #endif dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); /* XXX racey but good 'nuf? */ if ((IEEE80211_NODE_SAVEQ_QLEN(dataq) != 0) || (IEEE80211_NODE_SAVEQ_QLEN(mgtq) != 0)) { wbuf_t wbuf; IEEE80211_NODE_SAVEQ_LOCK(dataq); while (IEEE80211_NODE_SAVEQ_POLL(dataq, wbuf) != NULL && wbuf_get_age(wbuf) < IEEE80211_INACT_WAIT) { struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "discard frame, age %u \n", wbuf_get_age(wbuf)); IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); ieee80211_release_wbuf(ni,wbuf, &ts); discard++; } if (wbuf != NULL) wbuf_set_age(wbuf, wbuf_get_age(wbuf) - IEEE80211_INACT_WAIT); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); while (IEEE80211_NODE_SAVEQ_POLL(mgtq, wbuf) != NULL && wbuf_get_age(wbuf) < IEEE80211_INACT_WAIT) { struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "discard mgt frame, age %u \n", wbuf_get_age(wbuf)); IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); ieee80211_release_wbuf(ni,wbuf, &ts); discard++; } if (wbuf != NULL) wbuf_set_age(wbuf, wbuf_get_age(wbuf) - IEEE80211_INACT_WAIT); IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "discard %u frames for age \n", discard); IEEE80211_NODE_STAT_ADD(ni, ps_discard, discard); } if ((IEEE80211_NODE_SAVEQ_QLEN(dataq) == 0) && (IEEE80211_NODE_SAVEQ_QLEN(mgtq) == 0)) { #ifdef ATH_SWRETRY /* also check whether there is frame in tid q */ if (vap->iv_set_tim != NULL && (ni->ni_ic)->ic_exist_pendingfrm_tidq(ni->ni_ic, ni) !=0) #else if (vap->iv_set_tim != NULL) #endif vap->iv_set_tim(ni, 0, false); } return discard; }