⬢ DragonFlyBSD Kernel Audit
DF-3454 / fix.diff
← back to finding ↓ download raw
--- a/sys/netproto/802_11/wlan/ieee80211_amrr.c
+++ b/sys/netproto/802_11/wlan/ieee80211_amrr.c
@@ -254,6 +254,17 @@
 		rs = &ni->ni_rates;
 	}
 
+	/*
+	 * The node's HT status (and therefore the active rateset) can
+	 * change at any time (channel switch, re-association without
+	 * HT IEs, htrates cleared).  Never trust a stale index that
+	 * was computed against a different rateset.
+	 */
+	if (rs->rs_nrates == 0)
+		rix = 0;
+	else if (rix < 0 || rix >= rs->rs_nrates)
+		rix = rs->rs_nrates - 1;
+
 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
 	    "AMRR: current rate %d, txcnt=%d, retrycnt=%d",
 	    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
@@ -332,6 +343,16 @@
 		rs = &ni->ni_rates;
 	}
 
+	/*
+	 * Re-sync a stale index against the currently selected rateset
+	 * before it is used here or handed to drivers (which index
+	 * their own legacy rate tables with it).
+	 */
+	if (rs->rs_nrates == 0)
+		amn->amn_rix = 0;
+	else if (amn->amn_rix < 0 || amn->amn_rix >= rs->rs_nrates)
+		amn->amn_rix = rs->rs_nrates - 1;
+
 	if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) {
 		rix = amrr_update(amrr, amn, ni);
 		if (rix != amn->amn_rix) {
@@ -425,17 +446,24 @@
 	int rate;
 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
 	struct ieee80211_rateset *rs;
+	int rix;
 
 	/* XXX TODO: check locking? */
 
 	/* XXX TODO: this should be a method */
 	if (amrr_node_is_11n(ni)) {
 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
-		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+		rix = amn->amn_rix;
+		if (rix < 0 || rix >= rs->rs_nrates)
+			rix = (rs->rs_nrates == 0) ? 0 : rs->rs_nrates - 1;
+		rate = rs->rs_rates[rix] & IEEE80211_RATE_VAL;
 		sbuf_printf(s, "rate: MCS %d\n", rate);
 	} else {
 		rs = &ni->ni_rates;
-		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+		rix = amn->amn_rix;
+		if (rix < 0 || rix >= rs->rs_nrates)
+			rix = (rs->rs_nrates == 0) ? 0 : rs->rs_nrates - 1;
+		rate = rs->rs_rates[rix] & IEEE80211_RATE_VAL;
 		sbuf_printf(s, "rate: %d Mbit\n", rate / 2);
 	}