/*
 * 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;
}
Exemple #2
0
static int
amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
    struct ieee80211_node *ni)
{
	int rix = amn->amn_rix;

	KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));

	if (is_success(amn)) {
		amn->amn_success++;
		if (amn->amn_success >= amn->amn_success_threshold &&
		    rix + 1 < ni->ni_rates.rs_nrates) {
			amn->amn_recovery = 1;
			amn->amn_success = 0;
			rix++;
			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
			    "AMRR increasing rate %d (txcnt=%d retrycnt=%d)",
			    ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
			    amn->amn_txcnt, amn->amn_retrycnt);
		} else {
			amn->amn_recovery = 0;
		}
	} else if (is_failure(amn)) {
		amn->amn_success = 0;
		if (rix > 0) {
			if (amn->amn_recovery) {
				amn->amn_success_threshold *= 2;
				if (amn->amn_success_threshold >
				    amrr->amrr_max_success_threshold)
					amn->amn_success_threshold =
					    amrr->amrr_max_success_threshold;
			} else {
				amn->amn_success_threshold =
				    amrr->amrr_min_success_threshold;
			}
			rix--;
			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
			    "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)",
			    ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
			    amn->amn_txcnt, amn->amn_retrycnt);
		}
		amn->amn_recovery = 0;
	}

	/* reset counters */
	amn->amn_txcnt = 0;
	amn->amn_retrycnt = 0;

	return rix;
}
Exemple #3
0
static void
hwmp_peerdown(struct ieee80211_node *ni)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_meshperr_ie perr;
	struct ieee80211_mesh_route *rt;
	struct ieee80211_hwmp_route *hr;

	rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
	if (rt == NULL)
		return;
	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
	    "%s", "delete route entry");
	perr.perr_ttl = ms->ms_ttl;
	perr.perr_ndests = 1;
	PERR_DFLAGS(0) = 0;
	if (hr->hr_seq == 0)
		PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
	PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
	IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
	PERR_DSEQ(0) = hr->hr_seq;
	PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
	/* NB: flush everything passing through peer */
	ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
	hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
}
static void
amrr_node_init(struct ieee80211_node *ni)
{
	const struct ieee80211_rateset *rs = &ni->ni_rates;
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_amrr *amrr = vap->iv_rs;
	struct ieee80211_amrr_node *amn;

	if (ni->ni_rctls == NULL) {
		ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node),
		    M_80211_RATECTL, M_NOWAIT|M_ZERO);
		if (amn == NULL) {
			if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
			    "structure\n");
			return;
		}
	} else
		amn = ni->ni_rctls;
	amn->amn_amrr = amrr;
	amn->amn_success = 0;
	amn->amn_recovery = 0;
	amn->amn_txcnt = amn->amn_retrycnt = 0;
	amn->amn_success_threshold = amrr->amrr_min_success_threshold;

	/* pick initial rate */
	for (amn->amn_rix = rs->rs_nrates - 1;
	     amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72;
	     amn->amn_rix--)
		;
	ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
	amn->amn_ticks = ticks;

	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
	    "AMRR initial rate %d", ni->ni_txrate);
}
Exemple #5
0
/*
 * Handle power-save state change in station mode.
 */
void
ieee80211_sta_pwrsave(struct ieee80211vap *vap, int enable)
{
	struct ieee80211_node *ni = vap->iv_bss;

	if (!((enable != 0) ^ ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) != 0)))
		return;

	IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
	    "sta power save mode %s", enable ? "on" : "off");
	if (!enable) {
		ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
		ieee80211_send_nulldata(ieee80211_ref_node(ni));
		/*
		 * Flush any queued frames; we can do this immediately
		 * because we know they'll be queued behind the null
		 * data frame we send the ap.
		 * XXX can we use a data frame to take us out of ps?
		 */
		if (ni->ni_psq.psq_len != 0)
			pwrsave_flushq(ni);
	} else {
		ni->ni_flags |= IEEE80211_NODE_PWR_MGT;
		ieee80211_send_nulldata(ieee80211_ref_node(ni));
	}
}
/*
 * Validate and strip privacy headers (and trailer) for a
 * received frame that has the Protected Frame bit set.
 */
struct ieee80211_key *
ieee80211_crypto_decap(struct ieee80211_node *ni, struct sk_buff *skb, int hdrlen)
{
#define	IEEE80211_WEP_HDRLEN	(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
#define	IEEE80211_WEP_MINLEN \
	(sizeof(struct ieee80211_frame) + \
	IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_key *k;
	struct ieee80211_frame *wh;
	const struct ieee80211_cipher *cip;
	const u_int8_t *ivp;
	u_int8_t keyid;

	/* NB: this minimum size data frame could be bigger */
	if (skb->len < IEEE80211_WEP_MINLEN) {
		IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
			"%s: WEP data frame too short, len %u",
			__func__, skb->len);
		vap->iv_stats.is_rx_tooshort++;	/* XXX need unique stat? */
		return NULL;
	}
	/*
	 * Locate the key. If unicast and there is no unicast
	 * key then we fall back to the key id in the header.
	 * This assumes unicast keys are only configured when
	 * the key id in the header is meaningless (typically 0).
	 */
	wh = (struct ieee80211_frame *) skb->data;
	ivp = skb->data + hdrlen;
	keyid = ivp[IEEE80211_WEP_IVLEN];
	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none)
		k = &vap->iv_nw_keys[keyid >> 6];
	else
static void
amrr_node_init(struct ieee80211_node *ni)
{
	const struct ieee80211_rateset *rs = NULL;
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_amrr *amrr = vap->iv_rs;
	struct ieee80211_amrr_node *amn;
	uint8_t rate;

	if (ni->ni_rctls == NULL) {
		ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node),
		    M_80211_RATECTL, M_NOWAIT|M_ZERO);
		if (amn == NULL) {
			if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
			    "structure\n");
			return;
		}
	} else
		amn = ni->ni_rctls;

	amn->amn_amrr = amrr;
	amn->amn_success = 0;
	amn->amn_recovery = 0;
	amn->amn_txcnt = amn->amn_retrycnt = 0;
	amn->amn_success_threshold = amrr->amrr_min_success_threshold;

	rs = ieee80211_ratectl_get_rateset(ni);

	/* Initial rate - lowest */
	rate = rs->rs_rates[0];

	/* XXX clear the basic rate flag if it's not 11n */
	if (! ieee80211_ratectl_node_is11n(ni))
		rate &= IEEE80211_RATE_VAL;

	/* pick initial rate from the rateset - HT or otherwise */
	for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0;
	    amn->amn_rix--) {
		/* legacy - anything < 36mbit, stop searching */
		/* 11n - stop at MCS4 / MCS12 / MCS28 */
		if (ieee80211_ratectl_node_is11n(ni) &&
		    (rs->rs_rates[amn->amn_rix] & 0x7) < 4)
			break;
		else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72)
			break;
		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
	}

	/* if the rate is an 11n rate, ensure the MCS bit is set */
	if (ieee80211_ratectl_node_is11n(ni))
		rate |= IEEE80211_RATE_MCS;

	/* Assign initial rate from the rateset */
	ni->ni_txrate = rate;
	amn->amn_ticks = ticks;

	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
	    "%s: AMRR: nrates=%d, initial rate %d",
		__func__, rs->rs_nrates, rate);
}
Exemple #8
0
/*
 * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are
 * called when the vap is configured as a HWMP RANN root node.
 */
static void
hwmp_rootmode_rann_callout(void *arg)
{
	struct ieee80211vap *vap = (struct ieee80211vap *)arg;
	struct ieee80211_hwmp_state *hs;
	struct ieee80211_mesh_state *ms;
	struct ieee80211_meshrann_ie rann;

	wlan_serialize_enter();
	hs = vap->iv_hwmp;
	ms = vap->iv_mesh;
	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
	    "%s", "send broadcast RANN");

	rann.rann_flags = 0;
	if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
		rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
	rann.rann_hopcount = 0;
	rann.rann_ttl = ms->ms_ttl;
	IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
	rann.rann_seq = ++hs->hs_seq;
	rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL;

	vap->iv_stats.is_hwmp_rootrann++;
	hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann);
	hwmp_rootmode_setup(vap);
	wlan_serialize_exit();
}
static void
hwmp_rootmode_cb(void *arg)
{
	struct ieee80211vap *vap = (struct ieee80211vap *)arg;
	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_meshpreq_ie preq;

	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
	    "%s", "send broadcast PREQ");

	preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
	if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
		preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR;
	if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
		preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
	preq.preq_hopcount = 0;
	preq.preq_ttl = ms->ms_ttl;
	preq.preq_id = ++hs->hs_preqid;
	IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
	preq.preq_origseq = ++hs->hs_seq;
	preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout);
	preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
	preq.preq_tcount = 1;
	IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
	PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
	    IEEE80211_MESHPREQ_TFLAGS_RF;
	PREQ_TSEQ(0) = 0;
	vap->iv_stats.is_hwmp_rootreqs++;
	hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
	hwmp_rootmode_setup(vap);
}
/*
 * Handle station leaving bss.
 */
void
ieee80211_node_saveq_cleanup(struct ieee80211_node *ni)
{
    struct ieee80211vap *vap = ni->ni_vap;

    /* vap is already deleted */
    if (vap == NULL) return;

    if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
        ieee80211_mlme_node_leave(ni);
    }
    else {
        ieee80211node_clear_flag(ni, IEEE80211_NODE_PWR_MGT);
#if NOT_YET
        if (ieee80211node_has_flag(ni, IEEE80211_NODE_UAPSD_TRIG)) {
            ieee80211node_clear_flag(ni, IEEE80211_NODE_UAPSD_TRIG);
            IEEE80211_UAPSD_LOCK(ni->ni_ic);
            ni->ni_ic->ic_uapsdmaxtriggers--;
            IEEE80211_UAPSD_UNLOCK(ni->ni_ic);
        }
#endif
    }

    if ((ieee80211_node_saveq_drain(ni) != 0) && (vap->iv_set_tim != NULL))
        vap->iv_set_tim(ni, 0);
    IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
                       "%s %u sta's in ps mode \n", __func__,vap->iv_ps_sta);
}
Exemple #11
0
/*
 * Move frames from the ps q to the vap's send queue
 * and/or the driver's send queue; and kick the start
 * method for each, as appropriate.  Note we're careful
 * to preserve packet ordering here.
 */
static void
pwrsave_flushq(struct ieee80211_node *ni)
{
	struct ieee80211_psq *psq = &ni->ni_psq;
	struct ieee80211com *ic = ni->ni_ic;
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_psq_head *qhead;
	struct mbuf *parent_q = NULL, *ifp_q = NULL;
	struct mbuf *m;

	IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
	    "flush ps queue, %u packets queued", psq->psq_len);

	IEEE80211_PSQ_LOCK(psq);
	qhead = &psq->psq_head[0];	/* 802.11 frames */
	if (qhead->head != NULL) {
		/* XXX could dispatch through vap and check M_ENCAP */
		/* XXX need different driver interface */
		/* XXX bypasses q max and OACTIVE */
		parent_q = qhead->head;
		qhead->head = qhead->tail = NULL;
		qhead->len = 0;
	}

	qhead = &psq->psq_head[1];	/* 802.3 frames */
	if (qhead->head != NULL) {
		/* XXX need different driver interface */
		/* XXX bypasses q max and OACTIVE */
		ifp_q = qhead->head;
		qhead->head = qhead->tail = NULL;
		qhead->len = 0;
	}
	psq->psq_len = 0;
	IEEE80211_PSQ_UNLOCK(psq);

	/* NB: do this outside the psq lock */
	/* XXX packets might get reordered if parent is OACTIVE */
	/* parent frames, should be encapsulated */
	while (parent_q != NULL) {
		m = parent_q;
		parent_q = m->m_nextpkt;
		m->m_nextpkt = NULL;
		/* must be encapsulated */
		KASSERT((m->m_flags & M_ENCAP),
		    ("%s: parentq with non-M_ENCAP frame!\n",
		    __func__));
		(void) ieee80211_parent_xmitpkt(ic, m);
	}

	/* VAP frames, aren't encapsulated */
	while (ifp_q != NULL) {
		m = ifp_q;
		ifp_q = m->m_nextpkt;
		m->m_nextpkt = NULL;
		KASSERT((!(m->m_flags & M_ENCAP)),
		    ("%s: vapq with M_ENCAP frame!\n", __func__));
		(void) ieee80211_vap_xmitpkt(vap, m);
	}
}
Exemple #12
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_psq_age(struct ieee80211_node *ni)
{
	struct ieee80211_psq *psq = &ni->ni_psq;
	int discard = 0;

	if (psq->psq_len != 0) {
#ifdef IEEE80211_DEBUG
		struct ieee80211vap *vap = ni->ni_vap;
#endif
		struct ieee80211_psq_head *qhead;
		struct mbuf *m;

		IEEE80211_PSQ_LOCK(psq);
		qhead = &psq->psq_head[0];
	again:
		while ((m = qhead->head) != NULL &&
		    M_AGE_GET(m) < IEEE80211_INACT_WAIT) {
			IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
			     "discard frame, age %u", M_AGE_GET(m));
			if ((qhead->head = m->m_nextpkt) == NULL)
				qhead->tail = NULL;
			KASSERT(qhead->len > 0, ("qhead len %d", qhead->len));
			qhead->len--;
			KASSERT(psq->psq_len > 0, ("psq len %d", psq->psq_len));
			psq->psq_len--;
			psq_mfree(m);
			discard++;
		}
		if (qhead == &psq->psq_head[0]) { /* Algol-68 style for loop */
			qhead = &psq->psq_head[1];
			goto again;
		}
		if (m != NULL)
			M_AGE_SUB(m, IEEE80211_INACT_WAIT);
		IEEE80211_PSQ_UNLOCK(psq);

		IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
		    "discard %u frames for age", discard);
		IEEE80211_NODE_STAT_ADD(ni, ps_discard, discard);
	}
	return discard;
}
Exemple #13
0
void
ieee80211_notify_node_auth(struct ieee80211_node *ni)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ifnet *ifp = vap->iv_ifp;

	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth");

	notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr);
}
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);
            }
        }
    }

}
Exemple #15
0
/*
 * Handle station power-save state change.
 */
void
ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable)
{
	struct ieee80211vap *vap = ni->ni_vap;
	int update;

	update = 0;
	if (enable) {
		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
			vap->iv_ps_sta++;
			update = 1;
		}
		ni->ni_flags |= IEEE80211_NODE_PWR_MGT;
		IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
		    "power save mode on, %u sta's in ps mode", vap->iv_ps_sta);

		if (update)
			vap->iv_update_ps(vap, vap->iv_ps_sta);
	} else {
		if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) {
			vap->iv_ps_sta--;
			update = 1;
		}
		ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
		IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
		    "power save mode off, %u sta's in ps mode", vap->iv_ps_sta);

		/* NB: order here is intentional so TIM is clear before flush */
		if (vap->iv_set_tim != NULL)
			vap->iv_set_tim(ni, 0);
		if (update) {
			/* NB if no sta's in ps, driver should flush mc q */
			vap->iv_update_ps(vap, vap->iv_ps_sta);
		}
		if (ni->ni_psq.psq_len != 0)
			pwrsave_flushq(ni);
	}
}
Exemple #16
0
static void
hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
    const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
{
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_mesh_route *rt = NULL;
	struct ieee80211_hwmp_route *hr;
 	struct ieee80211_meshperr_ie pperr;
	int i, forward = 0;
#ifdef IEEE80211_DEBUG
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif

	/*
	 * Acceptance criteria: check if we received a PERR from a
	 * neighbor and forwarding is enabled.
	 */
	if (ni == vap->iv_bss ||
	    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
	    !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
		return;
	/*
	 * Find all routing entries that match and delete them.
	 */
	for (i = 0; i < perr->perr_ndests; i++) {
		rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
		if (rt == NULL)
			continue;
		hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
		if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 
		    HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
			ieee80211_mesh_rt_del(vap, rt->rt_dest);
			ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
			rt = NULL;
			forward = 1;
		}
	}
	/*
	 * Propagate the PERR if we previously found it on our routing table.
	 * XXX handle ndest > 1
	 */
	if (forward && perr->perr_ttl > 1) {
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "propagate PERR from %s", kether_ntoa(wh->i_addr2, ethstr));
		memcpy(&pperr, perr, sizeof(*perr));
		pperr.perr_ttl--;
		hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
		    &pperr);
	}
}
Exemple #17
0
void
ieee80211_notify_node_leave(struct ieee80211_node *ni)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ifnet *ifp = vap->iv_ifp;

	CURVNET_SET_QUIET(ifp->if_vnet);
	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave",
	    (ni == vap->iv_bss) ? "bss " : "");

	if (ni == vap->iv_bss) {
		rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
		if_link_state_change(ifp, LINK_STATE_DOWN);
	} else {
		/* fire off wireless event station leaving */
		notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr);
	}
	CURVNET_RESTORE();
}
Exemple #18
0
void
ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ifnet *ifp = vap->iv_ifp;

	CURVNET_SET_QUIET(ifp->if_vnet);
	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join",
	    (ni == vap->iv_bss) ? "bss " : "");

	if (ni == vap->iv_bss) {
		notify_macaddr(ifp, newassoc ?
		    RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid);
		if_link_state_change(ifp, LINK_STATE_UP);
	} else {
		notify_macaddr(ifp, newassoc ?
		    RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr);
	}
	CURVNET_RESTORE();
}
Exemple #19
0
void
ieee80211_amrr_node_init(struct ieee80211_amrr *amrr,
    struct ieee80211_amrr_node *amn, struct ieee80211_node *ni)
{
	const struct ieee80211_rateset *rs = &ni->ni_rates;

	amn->amn_amrr = amrr;
	amn->amn_success = 0;
	amn->amn_recovery = 0;
	amn->amn_txcnt = amn->amn_retrycnt = 0;
	amn->amn_success_threshold = amrr->amrr_min_success_threshold;

	/* pick initial rate */
	for (amn->amn_rix = rs->rs_nrates - 1;
	     amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72;
	     amn->amn_rix--)
		;
	ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
	amn->amn_ticks = ticks;

	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
	    "AMRR initial rate %d", ni->ni_txrate);
}
Exemple #20
0
/*
 * Examine and potentially adjust the transmit rate.
 */
static void
ath_rate_ctl(void *arg, struct ieee80211_node *ni)
{
    struct ath_softc *sc = arg;
    struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni));
    int rix;

#define is_success(amn) \
(amn->amn_tx_try1_cnt  < (amn->amn_tx_try0_cnt/10))
#define is_enough(amn) \
(amn->amn_tx_try0_cnt > 10)
#define is_failure(amn) \
(amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3))

    rix = amn->amn_rix;

    IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
                   "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d",
                   amn->amn_tx_try0_cnt, amn->amn_tx_try1_cnt, amn->amn_tx_try2_cnt,
                   amn->amn_tx_try3_cnt, amn->amn_success_threshold);
    if (is_success (amn) && is_enough (amn)) {
        amn->amn_success++;
        if (amn->amn_success == amn->amn_success_threshold &&
                rix + 1 < ni->ni_rates.rs_nrates) {
            amn->amn_recovery = 1;
            amn->amn_success = 0;
            rix++;
            IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
                           "increase rate to %d", rix);
        } else {
            amn->amn_recovery = 0;
        }
    } else if (is_failure (amn)) {
        amn->amn_success = 0;
        if (rix > 0) {
            if (amn->amn_recovery) {
                /* recovery failure. */
                amn->amn_success_threshold *= 2;
                amn->amn_success_threshold = min (amn->amn_success_threshold,
                                                  (u_int)ath_rate_max_success_threshold);
                IEEE80211_NOTE(ni->ni_vap,
                               IEEE80211_MSG_RATECTL, ni,
                               "decrease rate recovery thr: %d",
                               amn->amn_success_threshold);
            } else {
                /* simple failure. */
                amn->amn_success_threshold = ath_rate_min_success_threshold;
                IEEE80211_NOTE(ni->ni_vap,
                               IEEE80211_MSG_RATECTL, ni,
                               "decrease rate normal thr: %d",
                               amn->amn_success_threshold);
            }
            amn->amn_recovery = 0;
            rix--;
        } else {
            amn->amn_recovery = 0;
        }

    }
    if (is_enough (amn) || rix != amn->amn_rix) {
        /* reset counters. */
        amn->amn_tx_try0_cnt = 0;
        amn->amn_tx_try1_cnt = 0;
        amn->amn_tx_try2_cnt = 0;
        amn->amn_tx_try3_cnt = 0;
        amn->amn_tx_failure_cnt = 0;
    }
    if (rix != amn->amn_rix) {
        ath_rate_update(sc, ni, rix);
    }
}
Exemple #21
0
/**
 * The code below assumes that we are dealing with hardware multi rate retry
 * I have no idea what will happen if you try to use this module with another
 * type of hardware. Your machine might catch fire or it might work with
 * horrible performance...
 */
static void
ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)
{
    struct ath_node *an = ATH_NODE(ni);
    struct amrr_node *amn = ATH_NODE_AMRR(an);
    struct ieee80211vap *vap = ni->ni_vap;
    const HAL_RATE_TABLE *rt = sc->sc_currates;
    u_int8_t rix;

    KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));

    IEEE80211_NOTE(vap, IEEE80211_MSG_RATECTL, ni,
                   "%s: set xmit rate to %dM", __func__,
                   ni->ni_rates.rs_nrates > 0 ?
                   (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);

    amn->amn_rix = rate;
    /*
     * Before associating a node has no rate set setup
     * so we can't calculate any transmit codes to use.
     * This is ok since we should never be sending anything
     * but management frames and those always go at the
     * lowest hardware rate.
     */
    if (ni->ni_rates.rs_nrates > 0) {
        ni->ni_txrate = ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL;
        amn->amn_tx_rix0 = sc->sc_rixmap[ni->ni_txrate];
        amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode;
        amn->amn_tx_rate0sp = amn->amn_tx_rate0 |
                              rt->info[amn->amn_tx_rix0].shortPreamble;
        if (sc->sc_mrretry) {
            amn->amn_tx_try0 = 1;
            amn->amn_tx_try1 = 1;
            amn->amn_tx_try2 = 1;
            amn->amn_tx_try3 = 1;
            if (--rate >= 0) {
                rix = sc->sc_rixmap[
                          ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
                amn->amn_tx_rate1 = rt->info[rix].rateCode;
                amn->amn_tx_rate1sp = amn->amn_tx_rate1 |
                                      rt->info[rix].shortPreamble;
            } else {
                amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0;
            }
            if (--rate >= 0) {
                rix = sc->sc_rixmap[
                          ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
                amn->amn_tx_rate2 = rt->info[rix].rateCode;
                amn->amn_tx_rate2sp = amn->amn_tx_rate2 |
                                      rt->info[rix].shortPreamble;
            } else {
                amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0;
            }
            if (rate > 0) {
                /* NB: only do this if we didn't already do it above */
                amn->amn_tx_rate3 = rt->info[0].rateCode;
                amn->amn_tx_rate3sp =
                    amn->amn_tx_rate3 | rt->info[0].shortPreamble;
            } else {
                amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0;
            }
        } else {
            amn->amn_tx_try0 = ATH_TXMAXTRY;
            /* theorically, these statements are useless because
             *  the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY
             */
            amn->amn_tx_try1 = 0;
            amn->amn_tx_try2 = 0;
            amn->amn_tx_try3 = 0;
            amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0;
            amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0;
            amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0;
        }
    }
    node_reset(amn);

    amn->amn_interval = ath_rateinterval;
    if (vap->iv_opmode == IEEE80211_M_STA)
        amn->amn_interval /= 2;
    amn->amn_interval = (amn->amn_interval * hz) / 1000;
}
Exemple #22
0
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
	const struct ath_rc_series *rc, const struct ath_tx_status *ts,
	int frame_size, int nframes, int nbad)
{
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	int final_rix, short_tries, long_tries;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	int status = ts->ts_status;
	int mrr;

	final_rix = rt->rateCodeToIndex[ts->ts_rate];
	short_tries = ts->ts_shortretry;
	long_tries = ts->ts_longretry + 1;

	if (frame_size == 0)		    /* NB: should not happen */
		frame_size = 1500;

	if (sn->ratemask == 0) {
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		    &an->an_node,
		    "%s: size %d %s rate/try %d/%d no rates yet", 
		    __func__,
		    bin_to_size(size_to_bin(frame_size)),
		    status ? "FAIL" : "OK",
		    short_tries, long_tries);
		return;
	}
	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
	if (!mrr || ts->ts_finaltsi == 0) {
		if (!IS_RATE_DEFINED(sn, final_rix)) {
			badrate(ifp, 0, ts->ts_rate, long_tries, status);
			return;
		}
		/*
		 * Only one rate was used; optimize work.
		 */
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		     &an->an_node, "%s: size %d (%d bytes) %s rate/try %d %s/%d/%d nframes/nbad [%d/%d]",
		     __func__,
		     bin_to_size(size_to_bin(frame_size)),
		     frame_size,
		     status ? "FAIL" : "OK",
		     dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),
		     short_tries, long_tries, nframes, nbad);
		update_stats(sc, an, frame_size, 
			     final_rix, long_tries,
			     0, 0,
			     0, 0,
			     0, 0,
			     short_tries, long_tries, status,
			     nframes, nbad);
		update_ewma_stats(sc, an, frame_size, 
			     final_rix, long_tries,
			     0, 0,
			     0, 0,
			     0, 0,
			     short_tries, long_tries, status,
			     nframes, nbad);

	} else {
		int finalTSIdx = ts->ts_finaltsi;
		int i;

		/*
		 * Process intermediate rates that failed.
		 */

		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		    &an->an_node,
"%s: size %d (%d bytes) finaltsidx %d tries %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d] nframes/nbad [%d/%d]", 
		     __func__,
		     bin_to_size(size_to_bin(frame_size)),
		     frame_size,
		     finalTSIdx,
		     long_tries,
		     status ? "FAIL" : "OK",
		     dot11rate(rt, rc[0].rix),
		      dot11rate_label(rt, rc[0].rix), rc[0].tries,
		     dot11rate(rt, rc[1].rix),
		      dot11rate_label(rt, rc[1].rix), rc[1].tries,
		     dot11rate(rt, rc[2].rix),
		      dot11rate_label(rt, rc[2].rix), rc[2].tries,
		     dot11rate(rt, rc[3].rix),
		      dot11rate_label(rt, rc[3].rix), rc[3].tries,
		     nframes, nbad);

		for (i = 0; i < 4; i++) {
			if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))
				badrate(ifp, 0, rc[i].ratecode, rc[i].tries,
				    status);
		}

		/*
		 * NB: series > 0 are not penalized for failure
		 * based on the try counts under the assumption
		 * that losses are often bursty and since we
		 * sample higher rates 1 try at a time doing so
		 * may unfairly penalize them.
		 */
		if (rc[0].tries) {
			update_stats(sc, an, frame_size,
				     rc[0].rix, rc[0].tries,
				     rc[1].rix, rc[1].tries,
				     rc[2].rix, rc[2].tries,
				     rc[3].rix, rc[3].tries,
				     short_tries, long_tries,
				     long_tries > rc[0].tries,
				     nframes, nbad);
			long_tries -= rc[0].tries;
		}
		
		if (rc[1].tries && finalTSIdx > 0) {
			update_stats(sc, an, frame_size,
				     rc[1].rix, rc[1].tries,
				     rc[2].rix, rc[2].tries,
				     rc[3].rix, rc[3].tries,
				     0, 0,
				     short_tries, long_tries,
				     status,
				     nframes, nbad);
			long_tries -= rc[1].tries;
		}

		if (rc[2].tries && finalTSIdx > 1) {
			update_stats(sc, an, frame_size,
				     rc[2].rix, rc[2].tries,
				     rc[3].rix, rc[3].tries,
				     0, 0,
				     0, 0,
				     short_tries, long_tries,
				     status,
				     nframes, nbad);
			long_tries -= rc[2].tries;
		}

		if (rc[3].tries && finalTSIdx > 2) {
			update_stats(sc, an, frame_size,
				     rc[3].rix, rc[3].tries,
				     0, 0,
				     0, 0,
				     0, 0,
				     short_tries, long_tries,
				     status,
				     nframes, nbad);
		}

		update_ewma_stats(sc, an, frame_size,
			     rc[0].rix, rc[0].tries,
			     rc[1].rix, rc[1].tries,
			     rc[2].rix, rc[2].tries,
			     rc[3].rix, rc[3].tries,
			     short_tries, long_tries,
			     long_tries > rc[0].tries,
			     nframes, nbad);

	}
}
Exemple #23
0
static void
update_stats(struct ath_softc *sc, struct ath_node *an, 
		  int frame_size,
		  int rix0, int tries0,
		  int rix1, int tries1,
		  int rix2, int tries2,
		  int rix3, int tries3,
		  int short_tries, int tries, int status,
		  int nframes, int nbad)
{
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
#ifdef IEEE80211_DEBUG
	const HAL_RATE_TABLE *rt = sc->sc_currates;
#endif
	const int size_bin = size_to_bin(frame_size);
	const int size = bin_to_size(size_bin);
	int tt, tries_so_far;
	int is_ht40 = (an->an_node.ni_chw == 40);

	if (!IS_RATE_DEFINED(sn, rix0))
		return;
	tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries,
		MIN(tries0, tries) - 1, is_ht40);
	tries_so_far = tries0;

	if (tries1 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix1))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries,
			MIN(tries1 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
		tries_so_far += tries1;
	}

	if (tries2 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix2))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries,
			MIN(tries2 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
		tries_so_far += tries2;
	}

	if (tries3 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix3))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries,
			MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
	}

	if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
		/* just average the first few packets */
		int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
		int packets = sn->stats[size_bin][rix0].total_packets;
		sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);
	} else {
		/* use a ewma */
		sn->stats[size_bin][rix0].average_tx_time = 
			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 
			 (tt * (100 - ssc->smoothing_rate))) / 100;
	}
	
	/*
	 * XXX Don't mark the higher bit rates as also having failed; as this
	 * unfortunately stops those rates from being tasted when trying to
	 * TX. This happens with 11n aggregation.
	 */
	if (nframes == nbad) {
#if 0
		int y;
#endif
		sn->stats[size_bin][rix0].successive_failures += nbad;
#if 0
		for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
			/*
			 * Also say larger packets failed since we
			 * assume if a small packet fails at a
			 * bit-rate then a larger one will also.
			 */
			sn->stats[y][rix0].successive_failures += nbad;
			sn->stats[y][rix0].last_tx = ticks;
			sn->stats[y][rix0].tries += tries;
			sn->stats[y][rix0].total_packets += nframes;
		}
#endif
	} else {
		sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);
		sn->stats[size_bin][rix0].successive_failures = 0;
	}
	sn->stats[size_bin][rix0].tries += tries;
	sn->stats[size_bin][rix0].last_tx = ticks;
	sn->stats[size_bin][rix0].total_packets += nframes;

	if (rix0 == sn->current_sample_rix[size_bin]) {
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		   &an->an_node,
"%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d", 
		    __func__, 
		    size,
		    status ? "FAIL" : "OK",
		    dot11rate(rt, rix0),
		    dot11rate_label(rt, rix0),
		    short_tries, tries, tt, 
		    sn->stats[size_bin][rix0].average_tx_time,
		    sn->stats[size_bin][rix0].perfect_tx_time,
		    nframes, nbad);
		sn->sample_tt[size_bin] = tt;
		sn->current_sample_rix[size_bin] = -1;
	}
}
Exemple #24
0
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
		  int shortPreamble, size_t frameLen,
		  u_int8_t *rix0, int *try0, u_int8_t *txrate)
{
#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
#define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
#define	RATE(ix)	(DOT11RATE(ix) / 2)
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	const int size_bin = size_to_bin(frameLen);
	int rix, mrr, best_rix, change_rates;
	unsigned average_tx_time;

	ath_rate_update_static_rix(sc, &an->an_node);

	if (sn->static_rix != -1) {
		rix = sn->static_rix;
		*try0 = ATH_TXMAXTRY;
		goto done;
	}

	/* XXX TODO: this doesn't know about 11gn vs 11g protection; teach it */
	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);

	best_rix = pick_best_rate(an, rt, size_bin, !mrr);
	if (best_rix >= 0) {
		average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
	} else {
		average_tx_time = 0;
	}
	/*
	 * Limit the time measuring the performance of other tx
	 * rates to sample_rate% of the total transmission time.
	 */
	if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
		rix = pick_sample_rate(ssc, an, rt, size_bin);
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		     &an->an_node, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s",
		     average_tx_time,
		     sn->sample_tt[size_bin],
		     bin_to_size(size_bin),
		     dot11rate(rt, rix),
		     dot11rate_label(rt, rix),
		     dot11rate(rt, sn->current_rix[size_bin]),
		     dot11rate_label(rt, sn->current_rix[size_bin]));
		if (rix != sn->current_rix[size_bin]) {
			sn->current_sample_rix[size_bin] = rix;
		} else {
			sn->current_sample_rix[size_bin] = -1;
		}
		sn->packets_since_sample[size_bin] = 0;
	} else {
		change_rates = 0;
		if (!sn->packets_sent[size_bin] || best_rix == -1) {
			/* no packet has been sent successfully yet */
			change_rates = 1;
			if (an->an_node.ni_flags & IEEE80211_NODE_HT)
				best_rix =
				    ath_rate_pick_seed_rate_ht(sc, an, frameLen);
			else
				best_rix =
				    ath_rate_pick_seed_rate_legacy(sc, an, frameLen);
		} else if (sn->packets_sent[size_bin] < 20) {
			/* let the bit-rate switch quickly during the first few packets */
			IEEE80211_NOTE(an->an_node.ni_vap,
			    IEEE80211_MSG_RATECTL, &an->an_node,
			    "%s: switching quickly..", __func__);
			change_rates = 1;
		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
			/* min_switch seconds have gone by */
			IEEE80211_NOTE(an->an_node.ni_vap,
			    IEEE80211_MSG_RATECTL, &an->an_node,
			    "%s: min_switch %d > ticks_since_switch %d..",
			    __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);
			change_rates = 1;
		} else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&
		    (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {
			/* the current bit-rate is twice as slow as the best one */
			IEEE80211_NOTE(an->an_node.ni_vap,
			    IEEE80211_MSG_RATECTL, &an->an_node,
			    "%s: 2x att (= %d) < cur_rix att %d",
			    __func__,
			    2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);
			change_rates = 1;
		} else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {
			int cur_rix = sn->current_rix[size_bin];
			int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;
			/*
			 * If the node is HT, upgrade it if the MCS rate is
			 * higher and the average tx time is within 20% of
			 * the current rate. It can fail a little.
			 *
			 * This is likely not optimal!
			 */
#if 0
			printf("cur rix/att %x/%d, best rix/att %x/%d\n",
			    MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
#endif
			if ((MCS(best_rix) > MCS(cur_rix)) &&
			    (average_tx_time * 8) <= (cur_att * 10)) {
				IEEE80211_NOTE(an->an_node.ni_vap,
				    IEEE80211_MSG_RATECTL, &an->an_node,
				    "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d",
				    __func__,
				    MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att);
				change_rates = 1;
			}
		}

		sn->packets_since_sample[size_bin]++;
		
		if (change_rates) {
			if (best_rix != sn->current_rix[size_bin]) {
				IEEE80211_NOTE(an->an_node.ni_vap,
				    IEEE80211_MSG_RATECTL,
				    &an->an_node,
"%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
				    __func__,
				    bin_to_size(size_bin),
				    RATE(sn->current_rix[size_bin]),
				    sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
				    sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
				    RATE(best_rix),
				    sn->stats[size_bin][best_rix].average_tx_time,
				    sn->stats[size_bin][best_rix].perfect_tx_time,
				    sn->packets_since_switch[size_bin],
				    mrr);
			}
			sn->packets_since_switch[size_bin] = 0;
			sn->current_rix[size_bin] = best_rix;
			sn->ticks_since_switch[size_bin] = ticks;
			/* 
			 * Set the visible txrate for this node.
			 */
			an->an_node.ni_txrate = (rt->info[best_rix].phy == IEEE80211_T_HT) ?  MCS(best_rix) : DOT11RATE(best_rix);
		}
		rix = sn->current_rix[size_bin];
		sn->packets_since_switch[size_bin]++;
	}
	*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
done:
	KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));

	*rix0 = rix;
	*txrate = rt->info[rix].rateCode
		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
	sn->packets_sent[size_bin]++;
#undef DOT11RATE
#undef MCS
#undef RATE
}
Exemple #25
0
/*
 * Initialize the tables for a node.
 */
static void
ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
{
#define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
#define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
	struct ath_node *an = ATH_NODE(ni);
	const struct ieee80211_txparam *tp = ni->ni_txparms;
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	const HAL_RATE_TABLE *rt = sc->sc_currates;
#ifdef IEEE80211_DEBUG
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif
	int x, y, srate, rix;

	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));

	KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,
	    ("curmode %u", sc->sc_curmode));
	sn->sched = mrr_schedules[sc->sc_curmode];
	KASSERT(sn->sched != NULL,
	    ("no mrr schedule for mode %u", sc->sc_curmode));

        sn->static_rix = -1;
	if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
		/*
		 * A fixed rate is to be used; ucastrate is the IEEE code
		 * for this rate (sans basic bit).  Check this against the
		 * negotiated rate set for the node.  Note the fixed rate
		 * may not be available for various reasons so we only
		 * setup the static rate index if the lookup is successful.
		 * XXX handle MCS
		 */
		for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--)
			if (RATE(srate) == tp->ucastrate) {
				sn->static_rix = sc->sc_rixmap[tp->ucastrate];
				break;
			}
#ifdef IEEE80211_DEBUG
			if (sn->static_rix == -1) {
				IEEE80211_NOTE(ni->ni_vap,
				    IEEE80211_MSG_RATECTL, ni,
				    "%s: ucastrate %u not found, nrates %u",
				    __func__, tp->ucastrate,
				    ni->ni_rates.rs_nrates);
			}
#endif
	}

	/*
	 * Construct a bitmask of usable rates.  This has all
	 * negotiated rates minus those marked by the hal as
	 * to be ignored for doing rate control.
	 */
	sn->ratemask = 0;
	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
		rix = sc->sc_rixmap[RATE(x)];
		if (rix == 0xff)
			continue;
		/* skip rates marked broken by hal */
		if (!rt->info[rix].valid)
			continue;
		KASSERT(rix < SAMPLE_MAXRATES,
		    ("rate %u has rix %d", RATE(x), rix));
		sn->ratemask |= 1<<rix;
	}
#ifdef IEEE80211_DEBUG
	if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {
		uint32_t mask;

		ieee80211_note(ni->ni_vap, "[%s] %s: size 1600 rate/tt",
		    kether_ntoa(ni->ni_macaddr, ethstr), __func__);
		for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
			if ((mask & 1) == 0)
				continue;
			kprintf(" %d/%d", DOT11RATE(rix) / 2,
			    calc_usecs_unicast_packet(sc, 1600, rix, 0,0));
		}
		kprintf("\n");
	}
Exemple #26
0
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
	const struct ath_buf *bf)
{
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
	const struct ath_desc *ds0 = &bf->bf_desc[0];
	int final_rix, short_tries, long_tries, frame_size;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	int mrr;

	final_rix = rt->rateCodeToIndex[ts->ts_rate];
	short_tries = ts->ts_shortretry;
	long_tries = ts->ts_longretry + 1;
	frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
	if (frame_size == 0)		    /* NB: should not happen */
		frame_size = 1500;

	if (sn->ratemask == 0) {
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		    &an->an_node,
		    "%s: size %d %s rate/try %d/%d no rates yet", 
		    __func__,
		    bin_to_size(size_to_bin(frame_size)),
		    ts->ts_status ? "FAIL" : "OK",
		    short_tries, long_tries);
		return;
	}
	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
	if (!mrr || ts->ts_finaltsi == 0) {
		if (!IS_RATE_DEFINED(sn, final_rix)) {
			badrate(ifp, 0, ts->ts_rate, long_tries, ts->ts_status);
			return;
		}
		/*
		 * Only one rate was used; optimize work.
		 */
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		     &an->an_node, "%s: size %d %s rate/try %d/%d/%d",
		     __func__,
		     bin_to_size(size_to_bin(frame_size)),
		     ts->ts_status ? "FAIL" : "OK",
		     final_rix, short_tries, long_tries);
		update_stats(sc, an, frame_size, 
			     final_rix, long_tries,
			     0, 0,
			     0, 0,
			     0, 0,
			     short_tries, long_tries, ts->ts_status);
	} else {
		int hwrate0, rix0, tries0;
		int hwrate1, rix1, tries1;
		int hwrate2, rix2, tries2;
		int hwrate3, rix3, tries3;
		int finalTSIdx = ts->ts_finaltsi;

		/*
		 * Process intermediate rates that failed.
		 */
		if (sc->sc_ah->ah_magic != 0x20065416) {
			hwrate0 = MS(ds0->ds_ctl3, AR_XmitRate0);
			hwrate1 = MS(ds0->ds_ctl3, AR_XmitRate1);
			hwrate2 = MS(ds0->ds_ctl3, AR_XmitRate2);
			hwrate3 = MS(ds0->ds_ctl3, AR_XmitRate3);
		} else {
			hwrate0 = MS(ds0->ds_ctl3, AR5416_XmitRate0);
			hwrate1 = MS(ds0->ds_ctl3, AR5416_XmitRate1);
			hwrate2 = MS(ds0->ds_ctl3, AR5416_XmitRate2);
			hwrate3 = MS(ds0->ds_ctl3, AR5416_XmitRate3);
		}

		rix0 = rt->rateCodeToIndex[hwrate0];
		tries0 = MS(ds0->ds_ctl2, AR_XmitDataTries0);

		rix1 = rt->rateCodeToIndex[hwrate1];
		tries1 = MS(ds0->ds_ctl2, AR_XmitDataTries1);

		rix2 = rt->rateCodeToIndex[hwrate2];
		tries2 = MS(ds0->ds_ctl2, AR_XmitDataTries2);

		rix3 = rt->rateCodeToIndex[hwrate3];
		tries3 = MS(ds0->ds_ctl2, AR_XmitDataTries3);

		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		    &an->an_node,
"%s: size %d finaltsidx %d tries %d %s rate/try [%d/%d %d/%d %d/%d %d/%d]", 
		     __func__,
		     bin_to_size(size_to_bin(frame_size)),
		     finalTSIdx,
		     long_tries, 
		     ts->ts_status ? "FAIL" : "OK",
		     rix0, tries0,
		     rix1, tries1,
		     rix2, tries2,
		     rix3, tries3);

		if (tries0 && !IS_RATE_DEFINED(sn, rix0))
			badrate(ifp, 0, hwrate0, tries0, ts->ts_status);
		if (tries1 && !IS_RATE_DEFINED(sn, rix1))
			badrate(ifp, 1, hwrate1, tries1, ts->ts_status);
		if (tries2 && !IS_RATE_DEFINED(sn, rix2))
			badrate(ifp, 2, hwrate2, tries2, ts->ts_status);
		if (tries3 && !IS_RATE_DEFINED(sn, rix3))
			badrate(ifp, 3, hwrate3, tries3, ts->ts_status);

		/*
		 * NB: series > 0 are not penalized for failure
		 * based on the try counts under the assumption
		 * that losses are often bursty and since we
		 * sample higher rates 1 try at a time doing so
		 * may unfairly penalize them.
		 */
		if (tries0) {
			update_stats(sc, an, frame_size, 
				     rix0, tries0, 
				     rix1, tries1, 
				     rix2, tries2, 
				     rix3, tries3, 
				     short_tries, long_tries, 
				     long_tries > tries0);
			long_tries -= tries0;
		}
		
		if (tries1 && finalTSIdx > 0) {
			update_stats(sc, an, frame_size, 
				     rix1, tries1, 
				     rix2, tries2, 
				     rix3, tries3, 
				     0, 0, 
				     short_tries, long_tries, 
				     ts->ts_status);
			long_tries -= tries1;
		}

		if (tries2 && finalTSIdx > 1) {
			update_stats(sc, an, frame_size, 
				     rix2, tries2, 
				     rix3, tries3, 
				     0, 0,
				     0, 0,
				     short_tries, long_tries, 
				     ts->ts_status);
			long_tries -= tries2;
		}

		if (tries3 && finalTSIdx > 2) {
			update_stats(sc, an, frame_size, 
				     rix3, tries3, 
				     0, 0,
				     0, 0,
				     0, 0,
				     short_tries, long_tries, 
				     ts->ts_status);
		}
	}
}
Exemple #27
0
static void
update_stats(struct ath_softc *sc, struct ath_node *an, 
		  int frame_size,
		  int rix0, int tries0,
		  int rix1, int tries1,
		  int rix2, int tries2,
		  int rix3, int tries3,
		  int short_tries, int tries, int status)
{
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
	const int size_bin = size_to_bin(frame_size);
	const int size = bin_to_size(size_bin);
	int tt, tries_so_far;

	if (!IS_RATE_DEFINED(sn, rix0))
		return;
	tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries,
		MIN(tries0, tries) - 1);
	tries_so_far = tries0;

	if (tries1 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix1))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries,
			MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
		tries_so_far += tries1;
	}

	if (tries2 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix2))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries,
			MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
		tries_so_far += tries2;
	}

	if (tries3 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix3))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries,
			MIN(tries3 + tries_so_far, tries) - tries_so_far - 1);
	}

	if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
		/* just average the first few packets */
		int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
		int packets = sn->stats[size_bin][rix0].total_packets;
		sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
	} else {
		/* use a ewma */
		sn->stats[size_bin][rix0].average_tx_time = 
			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 
			 (tt * (100 - ssc->smoothing_rate))) / 100;
	}
	
	if (status != 0) {
		int y;
		sn->stats[size_bin][rix0].successive_failures++;
		for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
			/*
			 * Also say larger packets failed since we
			 * assume if a small packet fails at a
			 * bit-rate then a larger one will also.
			 */
			sn->stats[y][rix0].successive_failures++;
			sn->stats[y][rix0].last_tx = ticks;
			sn->stats[y][rix0].tries += tries;
			sn->stats[y][rix0].total_packets++;
		}
	} else {
		sn->stats[size_bin][rix0].packets_acked++;
		sn->stats[size_bin][rix0].successive_failures = 0;
	}
	sn->stats[size_bin][rix0].tries += tries;
	sn->stats[size_bin][rix0].last_tx = ticks;
	sn->stats[size_bin][rix0].total_packets++;

	if (rix0 == sn->current_sample_rix[size_bin]) {
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		   &an->an_node,
"%s: size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)", 
		    __func__, 
		    size,
		    status ? "FAIL" : "OK",
		    rix0, short_tries, tries, tt, 
		    sn->stats[size_bin][rix0].average_tx_time,
		    sn->stats[size_bin][rix0].perfect_tx_time);
		sn->sample_tt[size_bin] = tt;
		sn->current_sample_rix[size_bin] = -1;
	}
}
Exemple #28
0
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
		  int shortPreamble, size_t frameLen,
		  u_int8_t *rix0, int *try0, u_int8_t *txrate)
{
#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
#define	RATE(ix)	(DOT11RATE(ix) / 2)
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	const int size_bin = size_to_bin(frameLen);
	int rix, mrr, best_rix, change_rates;
	unsigned average_tx_time;

	if (sn->static_rix != -1) {
		rix = sn->static_rix;
		*try0 = ATH_TXMAXTRY;
		goto done;
	}

	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);

	best_rix = pick_best_rate(sn, rt, size_bin, !mrr);
	if (best_rix >= 0) {
		average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
	} else {
		average_tx_time = 0;
	}
	/*
	 * Limit the time measuring the performance of other tx
	 * rates to sample_rate% of the total transmission time.
	 */
	if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
		rix = pick_sample_rate(ssc, sn, rt, size_bin);
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		     &an->an_node, "size %u sample rate %d current rate %d",
		     bin_to_size(size_bin), RATE(rix),
		     RATE(sn->current_rix[size_bin]));
		if (rix != sn->current_rix[size_bin]) {
			sn->current_sample_rix[size_bin] = rix;
		} else {
			sn->current_sample_rix[size_bin] = -1;
		}
		sn->packets_since_sample[size_bin] = 0;
	} else {
		change_rates = 0;
		if (!sn->packets_sent[size_bin] || best_rix == -1) {
			/* no packet has been sent successfully yet */
			for (rix = rt->rateCount-1; rix > 0; rix--) {
				if ((sn->ratemask & (1<<rix)) == 0)
					continue;
				/* 
				 * Pick the highest rate <= 36 Mbps
				 * that hasn't failed.
				 */
				if (DOT11RATE(rix) <= 72 && 
				    sn->stats[size_bin][rix].successive_failures == 0) {
					break;
				}
			}
			change_rates = 1;
			best_rix = rix;
		} else if (sn->packets_sent[size_bin] < 20) {
			/* let the bit-rate switch quickly during the first few packets */
			change_rates = 1;
		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
			/* min_switch seconds have gone by */
			change_rates = 1;
		} else if (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time) {
			/* the current bit-rate is twice as slow as the best one */
			change_rates = 1;
		}

		sn->packets_since_sample[size_bin]++;
		
		if (change_rates) {
			if (best_rix != sn->current_rix[size_bin]) {
				IEEE80211_NOTE(an->an_node.ni_vap,
				    IEEE80211_MSG_RATECTL,
				    &an->an_node,
"%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
				    __func__,
				    bin_to_size(size_bin),
				    RATE(sn->current_rix[size_bin]),
				    sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
				    sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
				    RATE(best_rix),
				    sn->stats[size_bin][best_rix].average_tx_time,
				    sn->stats[size_bin][best_rix].perfect_tx_time,
				    sn->packets_since_switch[size_bin],
				    mrr);
			}
			sn->packets_since_switch[size_bin] = 0;
			sn->current_rix[size_bin] = best_rix;
			sn->ticks_since_switch[size_bin] = ticks;
			/* 
			 * Set the visible txrate for this node.
			 */
			an->an_node.ni_txrate = DOT11RATE(best_rix);
		}
		rix = sn->current_rix[size_bin];
		sn->packets_since_switch[size_bin]++;
	}
	*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
done:
	KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));

	*rix0 = rix;
	*txrate = rt->info[rix].rateCode
		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
	sn->packets_sent[size_bin]++;
#undef DOT11RATE
#undef RATE
}
Exemple #29
0
/*
 * Handle a station leaving an 11g network.
 */
static void
ieee80211_node_leave_11g(struct ieee80211_node *ni)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
   
    KASSERT((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan)
             || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)),
            ("not in 11g, bss %u:0x%x, curmode %u", vap->iv_bsschan->ic_freq,
             vap->iv_bsschan->ic_flags, ic->ic_curmode));

    KASSERT((ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP ||
             ni->ni_vap->iv_opmode == IEEE80211_M_BTAMP), (" node leave in invalid opmode "));

    /*
     * If a long slot station do the slot time bookkeeping.
     */
    if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
        if (ic->ic_longslotsta) {
           ic->ic_longslotsta--; 
           IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
                       "long slot time station leaves, count now %d",
                       ic->ic_longslotsta);
        } else {
#ifdef NOT_YET
           KASSERT(ic->ic_longslotsta > 0,
                ("bogus long slot station count %d", ic->ic_longslotsta));
#endif
           IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
                "bogus long slot station count %d", ic->ic_longslotsta);
        }

        if (ic->ic_longslotsta == 0) {
            /*
             * Re-enable use of short slot time if supported
             * and not operating in IBSS mode (per spec).
             */
            if (ic->ic_caps & IEEE80211_C_SHSLOT) {
                IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
                                  "%s: re-enable use of short slot time\n",
                                  __func__);
                ieee80211_set_shortslottime(ic, 1);
            }
        }
    }
    
    /*
     * If a non-ERP station do the protection-related bookkeeping.
     */
    if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
        KASSERT(ic->ic_nonerpsta > 0, ("bogus non-ERP station count %d", ic->ic_nonerpsta));
        ic->ic_nonerpsta--;
        IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
                       "non-ERP station leaves, count now %d", ic->ic_nonerpsta);
        if (ic->ic_nonerpsta == 0) {
	    struct ieee80211vap *tmpvap;
            ieee80211_update_erp_info(vap); 
            /* XXX verify mode? */
            if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
                IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
                                  "%s: re-enable use of short preamble\n",
                                  __func__);
                ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
                ic->ic_flags &= ~IEEE80211_F_USEBARKER;
            }
 	    TAILQ_FOREACH(tmpvap, &(ic)->ic_vaps, iv_next)
		ieee80211_vap_erpupdate_set(tmpvap);
        }
    }
}
Exemple #30
0
/*
 * Handle a station joining an 11g network.
 */
static void
ieee80211_node_join_11g(struct ieee80211_node *ni)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;

    KASSERT((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) ||
             IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)),
            ("not in 11g, bss %u:0x%x, curmode %u", vap->iv_bsschan->ic_freq,
             vap->iv_bsschan->ic_flags, ic->ic_curmode));

    KASSERT((ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP ||
             ni->ni_vap->iv_opmode == IEEE80211_M_BTAMP), (" node join in invalid opmode "));
    /*
     * Station isn't capable of short slot time.  Bump
     * the count of long slot time stations and disable
     * use of short slot time.  Note that the actual switch
     * over to long slot time use may not occur until the
     * next beacon transmission (per sec. 7.3.1.4 of 11g).
     */
    if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
        ic->ic_longslotsta++;
        IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
                       "station needs long slot time, count %d",
                       ic->ic_longslotsta);
        /* XXX vap's w/ conflicting needs won't work */
        if (!IEEE80211_IS_CHAN_108G(vap->iv_bsschan)) {
            /*
             * Don't force slot time when switched to turbo
             * mode as non-ERP stations won't be present; this
             * need only be done when on the normal G channel.
             */
            ieee80211_set_shortslottime(ic, 0);
        }
    }
    /*
     * If the new station is not an ERP station
     * then bump the counter and enable protection
     * if configured.
     */
    if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) {
        ic->ic_nonerpsta++;
        IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
                       "station is !ERP, %d non-ERP stations associated",
                       ic->ic_nonerpsta);
            /*
             * If protection is configured, enable it.
             */
            if (ic->ic_protmode != IEEE80211_PROT_NONE) {
                IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
                                  "%s: enable use of protection\n", __func__);
                ic->ic_flags |= IEEE80211_F_USEPROT;
                ic->ic_update_protmode(ic);
            }
            /*
             * If station does not support short preamble
             * then we must enable use of Barker preamble.
             */
            if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
                IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
                               "%s", "station needs long preamble");
                ic->ic_flags |= IEEE80211_F_USEBARKER;
                ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
            }

            /* Update ERP element if this is first non ERP station */
            if (ic->ic_nonerpsta == 1) {
	          struct ieee80211vap *tmpvap;
	          TAILQ_FOREACH(tmpvap, &(ic)->ic_vaps, iv_next)
		    ieee80211_vap_erpupdate_set(tmpvap);
	      }
    } else
        ni->ni_flags |= IEEE80211_NODE_ERP;
}