/* * 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; }
void ieee80211_node_saveq_get_info(struct ieee80211_node *ni, ieee80211_node_saveq_info *info) { struct node_powersave_queue *dataq,*mgtq; dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); IEEE80211_NODE_SAVEQ_LOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); info->data_count = IEEE80211_NODE_SAVEQ_QLEN(dataq); info->mgt_count = IEEE80211_NODE_SAVEQ_QLEN(mgtq); info->data_len = IEEE80211_NODE_SAVEQ_BYTES(dataq); info->mgt_len = IEEE80211_NODE_SAVEQ_BYTES(mgtq); info->ps_frame_count = mgtq->nsq_num_ps_frames; IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); }
void ieee80211_node_saveq_get_info(struct ieee80211_node *ni, ieee80211_node_saveq_info *info) { struct node_powersave_queue *dataq,*mgtq; #if LMAC_SUPPORT_POWERSAVE_QUEUE struct ieee80211com *ic = ni->ni_ic; ic->ic_node_pwrsaveq_get_info(ic, ni, info); return; #endif dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); IEEE80211_NODE_SAVEQ_LOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); info->data_count = IEEE80211_NODE_SAVEQ_QLEN(dataq); info->mgt_count = IEEE80211_NODE_SAVEQ_QLEN(mgtq); info->data_len = IEEE80211_NODE_SAVEQ_BYTES(dataq); info->mgt_len = IEEE80211_NODE_SAVEQ_BYTES(mgtq); info->ps_frame_count = mgtq->nsq_num_ps_frames; IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); }
/* * Clear any frames queued on a node's power save queue. * The number of frames that were present is returned. */ int ieee80211_node_saveq_drain(struct ieee80211_node *ni) { int qlen; struct node_powersave_queue *dataq,*mgtq; wbuf_t wbuf; struct ieee80211_tx_status ts; ts.ts_flags = IEEE80211_TX_ERROR; dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); qlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); qlen += IEEE80211_NODE_SAVEQ_QLEN(mgtq); /* * free all the frames. */ IEEE80211_NODE_SAVEQ_LOCK(dataq); IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); while(wbuf) { ieee80211_release_wbuf(ni,wbuf, &ts); IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); } IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); while(wbuf) { ieee80211_release_wbuf(ni,wbuf, &ts); IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); } IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); return qlen; }
/* * 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; #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); }
/* * Save an outbound packet for a node in power-save sleep state. * The new packet is placed on the node's saved queue, and the TIM * is changed, if necessary. */ void ieee80211_node_saveq_queue(struct ieee80211_node *ni, wbuf_t wbuf, u_int8_t frame_type) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; int qlen, age; struct node_powersave_queue *dataq,*mgtq,*psq; struct ieee80211_tx_status ts; #if LMAC_SUPPORT_POWERSAVE_QUEUE /* mark the frame and will give to ath layer */ wbuf_set_legacy_ps(wbuf); if (ic->ic_get_lmac_pwrsaveq_len(ic, ni, 0) == 0 && vap->iv_set_tim != NULL) { vap->iv_set_tim(ni, 1, false); } return; #endif 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) { psq = mgtq; } else { psq = dataq; } if (IEEE80211_NODE_SAVEQ_FULL(psq)) { IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, "%s pwr save q: overflow, drops (size %d) \n", (psq == dataq) ? "data" : "mgt", IEEE80211_PS_MAX_QUEUE); IEEE80211_NODE_STAT(ni,psq_drops); #ifdef IEEE80211_DEBUG if (ieee80211_msg_dumppkts(vap)) ieee80211_dump_pkt(ni->ni_ic, wtod(wbuf, caddr_t), wbuf_get_len(wbuf), -1, -1); #endif ts.ts_flags = IEEE80211_TX_ERROR; ieee80211_release_wbuf(ni,wbuf, &ts); return; } /* * special handling of frames with PS = 1. */ ieee80211_node_saveq_handle_ps_frames(ni,wbuf,frame_type); /* * Tag the frame with it's expiry time and insert * it in the queue. The aging interval is 4 times * the listen interval specified by the station. * Frames that sit around too long are reclaimed * using this information. */ age = ((ni->ni_intval * ic->ic_lintval) << 2) >> 10; /* TU -> secs */ /* * Note: our aging algorithm is not working well. In fact, due to the long interval * when the aging algorithm is called (IEEE80211_INACT_WAIT is 15 secs), we depend on * the associated station node to be disassociated to clear its stale frames. However, * as a temporary fix, I will make sure that the age is at least greater than * IEEE80211_INACT_WAIT. Otherwise, we will discard all frames in ps queue even though * it is just queued. */ if (age < IEEE80211_INACT_WAIT) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s Note: increased age from %d to %d secs.\n", __func__, age, IEEE80211_INACT_WAIT); age = IEEE80211_INACT_WAIT; } IEEE80211_NODE_SAVEQ_ENQUEUE(psq, wbuf, qlen, age); /* * calculate the combined queue length of management and data queues. */ qlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); qlen += IEEE80211_NODE_SAVEQ_QLEN(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s pwr queue:save frame, %u now queued \n", (psq == dataq) ? "data" : "mgt" ,qlen); if (qlen == 1 && vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 1, false); }
/* * 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; }
/* * 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); }
/* * Clear any frames queued on a node's power save queue. * The number of frames that were present is returned. */ int ieee80211_node_saveq_drain(struct ieee80211_node *ni) { int qlen; struct node_powersave_queue *dataq,*mgtq; wbuf_t wbuf; struct ieee80211_tx_status ts; //AUTELAN-Added-Begin:duanmingzhe for tid stuck int tidno = 0; u_int8_t subtype; struct ieee80211_frame *wh = NULL; struct ath_atx_tid *tid = NULL; struct ath_node *an = ((struct ath_node_net80211 *)(ni))->an_sta; struct ieee80211_frame_bar *bar; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = vap->iv_ic; osdev_t os_handle = ic->ic_osdev; struct ath_softc *sc = NULL; //AUTELAN-Added-End:duanmingzhe for tid stuck ts.ts_flags = IEEE80211_TX_ERROR; dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); qlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); qlen += IEEE80211_NODE_SAVEQ_QLEN(mgtq); /* * free all the frames. */ IEEE80211_NODE_SAVEQ_LOCK(dataq); IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); while(wbuf) { ieee80211_release_wbuf(ni,wbuf, &ts); IEEE80211_NODE_SAVEQ_DEQUEUE(dataq, wbuf); } IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); while(wbuf) { //AUTELAN-Added-Begin:duanmingzhe for tid stuck /****************************************** Before release the wbuf, we need to check the wbuf is bar frame? If it is, call ATH_TX_RESUME_TID,because ******************************************/ wh = (struct ieee80211_frame *)wbuf_header(wbuf); subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if(subtype == IEEE80211_FC0_SUBTYPE_BAR) { bar = (struct ieee80211_frame_bar *) wbuf_header(wbuf); tidno = (le16toh(bar->i_ctl) & IEEE80211_BAR_CTL_TID_M) >> IEEE80211_BAR_CTL_TID_S; tid = &an->an_tx_tid[tidno]; sc = an->an_sc; if(tid!=NULL) { ATH_TX_RESUME_TID(sc, tid); } } //AUTELAN-Added-End:duanmingzhe for tid stuck ieee80211_release_wbuf(ni,wbuf, &ts); IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, wbuf); }