static void ath_node_pwrsaveq_handle_ps_frames(struct ath_node *an, ath_wbuf_t athwbuf, u_int8_t frame_type) { #if ATH_DEBUG struct ath_softc *sc = an->an_sc; #endif struct ath_node_pwrsaveq *mgtq; ath_wbuf_t tmpathwbuf; mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); if (wbuf_is_pwrsaveframe(athwbuf->wbuf)) { /* ps frame (null (or) pspoll frame) */ ++mgtq->nsq_num_ps_frames; } else { /* non ps frame*/ if (mgtq->nsq_num_ps_frames) { struct ath_node_pwrsaveq *tmpq, temp_q; tmpq = &temp_q; ATH_NODE_PWRSAVEQ_INIT(tmpq); /* * go through the mgt queue and dump the frames with PS=1(pspoll,null). * accummulate the remaining frames into temp queue. */ for (;;) { ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, tmpathwbuf); if (tmpathwbuf == NULL) { break; } if (wbuf_is_pwrsaveframe(tmpathwbuf->wbuf)) { /* complete the wbuf */ DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s: send error, comple the wbuf\n", __func__); ath_node_pwrsaveq_complete_athwbuf(an, tmpathwbuf); } else { ATH_NODE_PWRSAVEQ_ADD(tmpq,tmpathwbuf); } } mgtq->nsq_num_ps_frames = 0; /* * move all the frames from temp queue to mgmt queue. */ for (;;) { ATH_NODE_PWRSAVEQ_DEQUEUE(tmpq, tmpathwbuf); if (tmpathwbuf == NULL) { break; } ATH_NODE_PWRSAVEQ_ADD(mgtq, tmpathwbuf); } } } }
static void ieee80211_node_saveq_handle_ps_frames(struct ieee80211_node *ni, wbuf_t wbuf, u_int8_t frame_type) { struct node_powersave_queue *mgtq; wbuf_t tmpwbuf; mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); if (wbuf_is_pwrsaveframe(wbuf)) { /* ps frame (null (or) pspoll frame) */ ++mgtq->nsq_num_ps_frames; } else { /* non ps frame*/ if (mgtq->nsq_num_ps_frames) { struct ieee80211_tx_status ts; struct node_powersave_queue *tmpq, temp_q; tmpq = &temp_q; IEEE80211_NODE_SAVEQ_INIT(tmpq); /* * go through the mgt queue and dump the frames with PS=1(pspoll,null). * accummulate the remaining frames into temp queue. */ for (;;) { IEEE80211_NODE_SAVEQ_DEQUEUE(mgtq, tmpwbuf); if (tmpwbuf == NULL) { break; } if (wbuf_is_pwrsaveframe(tmpwbuf)) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ANY, ni, "%s pwr save q: complete the PS frame with error \n", __func__); ts.ts_flags = IEEE80211_TX_ERROR; ieee80211_release_wbuf(ni,tmpwbuf, &ts); } else { IEEE80211_NODE_SAVEQ_ADD(tmpq,tmpwbuf); } } mgtq->nsq_num_ps_frames = 0; /* * move all the frames from temp queue to mgmt queue. */ for (;;) { IEEE80211_NODE_SAVEQ_DEQUEUE(tmpq, tmpwbuf); if (tmpwbuf == NULL) { break; } IEEE80211_NODE_SAVEQ_ADD(mgtq, tmpwbuf); } } } }
/* * 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 ath_node_pwrsaveq_send(ath_node_t node, u_int8_t frame_type) { struct ath_node *an = ATH_NODE(node); struct ath_softc *sc = an->an_sc; ath_wbuf_t athwbuf; wbuf_t wbuf = NULL; int qlen; struct ath_node_pwrsaveq *dataq, *mgtq; ieee80211_tx_control_t *txctl; struct ieee80211_frame *wh; u_int8_t more_frag; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); next_frag: ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_LOCK(mgtq); if (frame_type == IEEE80211_FC0_TYPE_MGT) { ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); if (athwbuf) wbuf = athwbuf->wbuf; if (wbuf && wbuf_is_pwrsaveframe(wbuf)) { /* ps frame (null (or) pspoll frame) */ --mgtq->nsq_num_ps_frames; } } else { ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); if (athwbuf) wbuf = athwbuf->wbuf; } if (athwbuf == NULL || wbuf == NULL) { ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); return 0; } qlen = ATH_NODE_PWRSAVEQ_QLEN(dataq); qlen += ATH_NODE_PWRSAVEQ_QLEN(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); wh = (struct ieee80211_frame *)wbuf_header(wbuf); more_frag = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG; /* * 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) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "send packet, %u still queued \n", qlen); /* * encap will set more data bit. */ wbuf_set_moredata(wbuf); if (wbuf_is_moredata(wbuf)) { wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; } } else { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s", "send packet, queue empty \n"); /* TIM bit will be set by UMAC caller */ } wbuf_clear_legacy_ps(wbuf); txctl = &athwbuf->txctl; if (sc->sc_ath_ops.tx(sc, wbuf, txctl) != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s: send error, comple the wbuf\n", __func__); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); /* process all fragment together */ if (more_frag) goto next_frag; return 0; } if (athwbuf) { OS_FREE_PS(athwbuf); } /* process all fragments together */ if (more_frag) goto next_frag; return 1; }
/* * 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; }