/*
 * 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;
}
示例#2
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;
}