/* * node saveq flush. */ void ieee80211_node_saveq_flush(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; wbuf_t wbuf; struct node_powersave_queue *dataq,*mgtq; int dqlen, mqlen; #if LMAC_SUPPORT_POWERSAVE_QUEUE struct ieee80211com *ic = ni->ni_ic; ic->ic_node_pwrsaveq_flush(ic, ni); if (vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 0, false); return; #endif dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); /* XXX if no stations in ps mode, flush mc frames */ dqlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); /* * Flush queued mgmt frames. */ IEEE80211_NODE_SAVEQ_LOCK(mgtq); if (IEEE80211_NODE_SAVEQ_QLEN(mgtq) != 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "flush mgt ps queue, %u packets queued \n", IEEE80211_NODE_SAVEQ_QLEN(mgtq)); for (;;) { IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); if (wbuf == NULL) break; mqlen = IEEE80211_NODE_SAVEQ_QLEN(mgtq); /* * For a Station node (non bss node) If this is the last packet, turn off the TIM bit, * Set the PWR_SAV bit on every frame but the last one * to allow encap to test for * adding more MORE_DATA bit to wh. */ if ((ni != ni->ni_bss_node) && (mqlen || dqlen)) { wbuf_set_moredata(wbuf); } ieee80211_send_mgmt(ni->ni_vap,ni,wbuf,false); } } mgtq->nsq_num_ps_frames = 0; IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); /* * Flush queued unicast frames. */ IEEE80211_NODE_SAVEQ_LOCK(dataq); if (IEEE80211_NODE_SAVEQ_QLEN(dataq) != 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "flush data ps queue, %u packets queued \n", IEEE80211_NODE_SAVEQ_QLEN(dataq)); for (;;) { IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); if (wbuf == NULL) break; dqlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "senddata ps queue, %u packets remaining \n", dqlen); /* * For a Station node (non bss node) If this is the last packet, turn off the TIM bit, * Set the PWR_SAV bit on every frame but the last one * to allow encap to test for * adding more MORE_DATA bit to wh. */ if ((ni != ni->ni_bss_node) && dqlen) { wbuf_set_moredata(wbuf); } ieee80211_send_wbuf(vap,ni, wbuf); } } IEEE80211_NODE_SAVEQ_UNLOCK(dataq); #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); }
/* * send one frme out of power save queue . * called in reponse to PS poll. * returns 1 if succesfully sends a frame. 0 other wise. */ int ieee80211_node_saveq_send(struct ieee80211_node *ni, int frame_type) { struct ieee80211vap *vap = ni->ni_vap; wbuf_t wbuf; int qlen; struct node_powersave_queue *dataq,*mgtq; /* * do not send any frames if the vap is paused. * wait until the vap is unpaused. */ if (ieee80211_vap_is_paused(vap)) return 0; dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); IEEE80211_NODE_SAVEQ_LOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); if (frame_type == IEEE80211_FC0_TYPE_MGT) { IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); if (wbuf && wbuf_is_pwrsaveframe(wbuf)) { /* ps frame (null (or) pspoll frame) */ --mgtq->nsq_num_ps_frames; } } else { IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); } if (wbuf == NULL) { IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); return 0; } qlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); qlen += IEEE80211_NODE_SAVEQ_QLEN(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); /* * If there are more packets, set the more packets bit * in the packet dispatched to the station; otherwise * turn off the TIM bit. */ if (qlen != 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "send packet, %u still queued \n", qlen); /* * encap will set more data bit. */ wbuf_set_moredata(wbuf); } else { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s", "send packet, queue empty \n"); #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); } if (frame_type == IEEE80211_FC0_TYPE_MGT) { /* send the management frame down to the ath */ ieee80211_send_mgmt(vap,ni,wbuf,true); } else { /* send the data down to the ath */ ieee80211_send_wbuf(vap,ni,wbuf); } return 1; }
/* * node saveq flush. */ void ieee80211_node_saveq_flush(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; wbuf_t wbuf; struct node_powersave_queue *dataq,*mgtq; int dqlen, mqlen; dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); /* XXX if no stations in ps mode, flush mc frames */ dqlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); /* * Flush queued mgmt frames. */ IEEE80211_NODE_SAVEQ_LOCK(mgtq); if (IEEE80211_NODE_SAVEQ_QLEN(mgtq) != 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "flush mgt ps queue, %u packets queued \n", IEEE80211_NODE_SAVEQ_QLEN(mgtq)); for (;;) { IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); if (wbuf == NULL) break; mqlen = IEEE80211_NODE_SAVEQ_QLEN(mgtq); /* * For a Station node (non bss node) If this is the last packet, turn off the TIM bit, * Set the PWR_SAV bit on every frame but the last one * to allow encap to test for * adding more MORE_DATA bit to wh. */ if ((ni != ni->ni_bss_node) && (mqlen || dqlen)) { wbuf_set_moredata(wbuf); } /* force send management frame so that the frames will not loop back into the save queue again */ ieee80211_send_mgmt(ni->ni_vap,ni,wbuf,true); } } mgtq->nsq_num_ps_frames = 0; IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); /* * Flush queued unicast frames. */ IEEE80211_NODE_SAVEQ_LOCK(dataq); if (IEEE80211_NODE_SAVEQ_QLEN(dataq) != 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "flush data ps queue, %u packets queued \n", IEEE80211_NODE_SAVEQ_QLEN(dataq)); for (;;) { IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); if (wbuf == NULL) break; dqlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "senddata ps queue, %u packets remaining \n", dqlen); /* * For a Station node (non bss node) If this is the last packet, turn off the TIM bit, * Set the PWR_SAV bit on every frame but the last one * to allow encap to test for * adding more MORE_DATA bit to wh. */ if ((ni != ni->ni_bss_node) && dqlen) { wbuf_set_moredata(wbuf); } ieee80211_send_wbuf(vap,ni, wbuf); } } IEEE80211_NODE_SAVEQ_UNLOCK(dataq); if (vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 0); }