/*
 * 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;
}
Example #2
0
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);
            }
        }
    }

}
Example #3
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;

    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;
}
Example #4
0
/*
 * 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);
}
Example #5
0
/*
 * 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;
}
Example #6
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);
    }