From 9c541f04510d62e8103483f81650a1649e9a9231 Mon Sep 17 00:00:00 2001 From: stsp Date: Mon, 8 Nov 2021 14:51:30 +0000 Subject: [PATCH] Send MiRA source files to the Attic. These files were unhooked from the build in April 2021. --- sys/net80211/ieee80211_mira.c | 1276 --------------------------------- sys/net80211/ieee80211_mira.h | 121 ---- 2 files changed, 1397 deletions(-) delete mode 100644 sys/net80211/ieee80211_mira.c delete mode 100644 sys/net80211/ieee80211_mira.h diff --git a/sys/net80211/ieee80211_mira.c b/sys/net80211/ieee80211_mira.c deleted file mode 100644 index bceb55f83a6..00000000000 --- a/sys/net80211/ieee80211_mira.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* $OpenBSD: ieee80211_mira.c,v 1.30 2020/05/01 14:04:17 stsp Exp $ */ - -/* - * Copyright (c) 2016 Stefan Sperling - * Copyright (c) 2016 Theo Buehler - * Copyright (c) 2006 Damien Bergamini - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -/* Allow for aggressive down probing when channel quality changes. */ -#define MIRA_AGGRESSIVE_DOWNWARDS_PROBING - -const struct ieee80211_ht_rateset * ieee80211_mira_get_rateset(int, int); -void ieee80211_mira_probe_timeout_up(void *); -void ieee80211_mira_probe_timeout_down(void *); -uint64_t ieee80211_mira_get_txrate(int, int); -uint16_t ieee80211_mira_legacy_txtime(uint32_t, int, struct ieee80211com *); -uint32_t ieee80211_mira_ht_txtime(uint32_t, int, int, int); -int ieee80211_mira_best_basic_rate(struct ieee80211_node *); -int ieee80211_mira_ack_rate(struct ieee80211_node *); -uint64_t ieee80211_mira_toverhead(struct ieee80211_mira_node *, - struct ieee80211com *, struct ieee80211_node *); -void ieee80211_mira_update_stats(struct ieee80211_mira_node *, - struct ieee80211com *, struct ieee80211_node *); -void ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *); -void ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *); -int ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *, - struct ieee80211_node *); -int ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *, - struct ieee80211_node *); -const struct ieee80211_ht_rateset * ieee80211_mira_next_rateset( - struct ieee80211_mira_node *, struct ieee80211_node *); -int ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *, - const struct ieee80211_ht_rateset *); -void ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *, - struct ieee80211_node *, const struct ieee80211_ht_rateset *); -int ieee80211_mira_next_mcs(struct ieee80211_mira_node *, - struct ieee80211_node *); -int ieee80211_mira_prev_mcs(struct ieee80211_mira_node *, - struct ieee80211_node *); -int ieee80211_mira_probe_valid(struct ieee80211_mira_node *, - struct ieee80211_node *); -void ieee80211_mira_probe_done(struct ieee80211_mira_node *); -int ieee80211_mira_intra_mode_ra_finished( - struct ieee80211_mira_node *, struct ieee80211_node *); -void ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn, - struct ieee80211_node *); -int ieee80211_mira_inter_mode_ra_finished( - struct ieee80211_mira_node *, struct ieee80211_node *); -int ieee80211_mira_best_rate(struct ieee80211_mira_node *, - struct ieee80211_node *); -void ieee80211_mira_update_probe_interval( - struct ieee80211_mira_goodput_stats *); -void ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *, - struct ieee80211_node *); -int ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *, - struct ieee80211_node *); -void ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *, - struct ieee80211_node *); -int ieee80211_mira_valid_tx_mcs(struct ieee80211com *, int); -uint32_t ieee80211_mira_valid_rates(struct ieee80211com *, - struct ieee80211_node *); -uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int, int); -void ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *, - struct ieee80211com *, struct ieee80211_node *); -void ieee80211_mira_reset_collision_stats(struct ieee80211_mira_node *); - -/* We use fixed point arithmetic with 64 bit integers. */ -#define MIRA_FP_SHIFT 21 -#define MIRA_FP_INT(x) (x ## ULL << MIRA_FP_SHIFT) /* the integer x */ -#define MIRA_FP_1 MIRA_FP_INT(1) - -/* Multiply two fixed point numbers. */ -#define MIRA_FP_MUL(a, b) \ - (((a) * (b)) >> MIRA_FP_SHIFT) - -/* Divide two fixed point numbers. */ -#define MIRA_FP_DIV(a, b) \ - (b == 0 ? (uint64_t)-1 : (((a) << MIRA_FP_SHIFT) / (b))) - -#ifdef MIRA_DEBUG -#define DPRINTF(x) do { if (mira_debug > 0) printf x; } while (0) -#define DPRINTFN(n, x) do { if (mira_debug >= (n)) printf x; } while (0) -int mira_debug = 0; -#else -#define DPRINTF(x) do { ; } while (0) -#define DPRINTFN(n, x) do { ; } while (0) -#endif - -#ifdef MIRA_DEBUG -void -mira_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp) -{ - uint64_t tmp; - - /* integer part */ - *i = (fp >> MIRA_FP_SHIFT); - - /* fractional part */ - tmp = (fp & ((uint64_t)-1 >> (64 - MIRA_FP_SHIFT))); - tmp *= 100; - *f = (uint32_t)(tmp >> MIRA_FP_SHIFT); -} - -char * -mira_fp_sprintf(uint64_t fp) -{ - uint32_t i, f; - static char buf[64]; - int ret; - - mira_fixedp_split(&i, &f, fp); - ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f); - if (ret == -1 || ret >= sizeof(buf)) - return "ERR"; - - return buf; -} - -void -mira_print_driver_stats(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) { - DPRINTF(("%s driver stats:\n", ether_sprintf(ni->ni_macaddr))); - DPRINTF(("mn->frames = %u\n", mn->frames)); - DPRINTF(("mn->retries = %u\n", mn->retries)); - DPRINTF(("mn->txfail = %u\n", mn->txfail)); - DPRINTF(("mn->ampdu_size = %u\n", mn->ampdu_size)); - DPRINTF(("mn->agglen = %u\n", mn->agglen)); -} -#endif /* MIRA_DEBUG */ - -const struct ieee80211_ht_rateset * -ieee80211_mira_get_rateset(int mcs, int sgi) -{ - const struct ieee80211_ht_rateset *rs; - int i; - - for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) { - rs = &ieee80211_std_ratesets_11n[i]; - if (sgi != rs->sgi) - continue; - if (mcs >= rs->min_mcs && mcs <= rs->max_mcs) - return rs; - } - - panic("MCS %d is not part of any rateset", mcs); -} - -/* - * Probe timers. - */ - -/* Constants related to timeouts for time-driven rate probing. */ -#define IEEE80211_MIRA_PROBE_TIMEOUT_MIN 2 /* in msec */ -#define IEEE80211_MIRA_PROBE_INTVAL_MAX (1 << 10) /* 2^10 */ - -void -ieee80211_mira_probe_timeout_up(void *arg) -{ - struct ieee80211_mira_node *mn = arg; - int s; - - s = splnet(); - mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] = 1; - DPRINTFN(3, ("probe up timeout fired\n")); - splx(s); -} - -void -ieee80211_mira_probe_timeout_down(void *arg) -{ - struct ieee80211_mira_node *mn = arg; - int s; - - s = splnet(); - mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN] = 1; - DPRINTFN(3, ("probe down timeout fired\n")); - splx(s); -} - -/* - * Update goodput statistics. - */ - -uint64_t -ieee80211_mira_get_txrate(int mcs, int sgi) -{ - const struct ieee80211_ht_rateset *rs; - uint64_t txrate; - - rs = ieee80211_mira_get_rateset(mcs, sgi); - txrate = rs->rates[mcs - rs->min_mcs]; - txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */ - txrate *= 500; /* convert to kbit/s */ - txrate /= 1000; /* convert to mbit/s */ - - return txrate; -} - -/* Based on rt2661_txtime in the ral(4) driver. */ -uint16_t -ieee80211_mira_legacy_txtime(uint32_t len, int rate, struct ieee80211com *ic) -{ -#define MIRA_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) - uint16_t txtime; - - if (MIRA_RATE_IS_OFDM(rate)) { - /* IEEE Std 802.11g-2003, pp. 44 */ - txtime = (8 + 4 * len + 3 + rate - 1) / rate; - txtime = 16 + 4 + 4 * txtime + 6; - } else { - /* IEEE Std 802.11b-1999, pp. 28 */ - txtime = (16 * len + rate - 1) / rate; - if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) - txtime += 72 + 24; - else - txtime += 144 + 48; - } - return txtime; -} - -uint32_t -ieee80211_mira_ht_txtime(uint32_t len, int mcs, int is2ghz, int sgi) -{ - const struct ieee80211_ht_rateset *rs; - /* XXX These constants should be macros in ieee80211.h instead. */ - const uint32_t t_lstf = 8; /* usec legacy short training field */ - const uint32_t t_lltf = 8; /* usec legacy long training field */ - const uint32_t t_lsig = 4; /* usec legacy signal field */ - const uint32_t t_htstf = 4; /* usec HT short training field */ - const uint32_t t_ltstf = 4; /* usec HT long training field */ - const uint32_t t_htsig = 8; /* usec HT signal field */ - const uint32_t t_sym = 4; /* usec symbol interval */ - const uint32_t t_syms = 3; /* usec symbol interval; XXX actually 3.6 */ - uint32_t n_sym, n_dbps; - uint32_t t_plcp; - uint32_t t_data; - uint32_t txtime; - - /* - * Calculate approximate frame Tx time in usec. - * See 802.11-2012, 20.4.3 "TXTIME calculation" and - * 20.3.11.1 "Equation (20-32)". - * XXX Assumes a 20MHz channel, HT-mixed frame format, no STBC. - */ - t_plcp = t_lstf + t_lltf + t_lsig + t_htstf + 4 * t_ltstf + t_htsig; - rs = ieee80211_mira_get_rateset(mcs, sgi); - n_dbps = rs->rates[mcs - rs->min_mcs] * 2; - n_sym = ((8 * len + 16 + 6) / n_dbps); /* "Equation (20-32)" */ - if (sgi) - t_data = (t_syms * n_sym) / t_sym; - else - t_data = t_sym * n_sym; - - txtime = t_plcp + t_data; - if (is2ghz) - txtime += 6; /* aSignalExtension */ - - return txtime; -} - -int -ieee80211_mira_best_basic_rate(struct ieee80211_node *ni) -{ - struct ieee80211_rateset *rs = &ni->ni_rates; - int i, best, rval; - - /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */ - best = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? 2 : 12; - - for (i = 0; i < rs->rs_nrates; i++) { - if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0) - continue; - rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); - if (rval > best) - best = rval; - } - - return best; -} - -/* - * See 802.11-2012, 9.7.6.5 "Rate selection for control response frames". - */ -int -ieee80211_mira_ack_rate(struct ieee80211_node *ni) -{ - /* - * Assume the ACK was sent at a mandatory ERP OFDM rate. - * In the worst case, the driver has retried at non-HT rates, - * so for MCS 0 assume we didn't actually send an OFDM frame - * and ACKs arrived at a basic rate. - */ - if (ni->ni_txmcs == 0) - return ieee80211_mira_best_basic_rate(ni); - else if (ni->ni_txmcs == 1) - return 12; /* 6 Mbit/s */ - else if (ni->ni_txmcs >= 2) - return 24; /* 12 Mbit/s */ - else - return 48; /* 24 Mbit/s */ -} - -uint64_t -ieee80211_mira_toverhead(struct ieee80211_mira_node *mn, - struct ieee80211com *ic, struct ieee80211_node *ni) -{ -/* XXX These should be macros in ieee80211.h. */ -#define MIRA_RTSLEN IEEE80211_MIN_LEN -#define MIRA_CTSLEN (sizeof(struct ieee80211_frame_cts) + IEEE80211_CRC_LEN) - uint32_t overhead; - uint64_t toverhead; - int rate, rts; - enum ieee80211_htprot htprot; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - - overhead = ieee80211_mira_ht_txtime(0, ni->ni_txmcs, - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), sgi); - - htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); - if (htprot == IEEE80211_HTPROT_NONMEMBER || - htprot == IEEE80211_HTPROT_NONHT_MIXED) - rts = 1; - else if (htprot == IEEE80211_HTPROT_20MHZ && - (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40)) - rts = 1; - else - rts = (mn->ampdu_size > ieee80211_mira_get_rts_threshold(mn, - ic, ni, mn->ampdu_size)); - - if (rts) { - /* Assume RTS/CTS were sent at a basic rate. */ - rate = ieee80211_min_basic_rate(ic); - overhead += ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rate, ic); - overhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rate, ic); - } - - if (mn->agglen == 1) { - /* Single-frame transmissions must wait for an ACK frame. */ - rate = ieee80211_mira_ack_rate(ni); - overhead += ieee80211_mira_legacy_txtime(IEEE80211_ACK_LEN, - rate, ic); - } - - toverhead = overhead; - toverhead <<= MIRA_FP_SHIFT; /* convert to fixed-point */ - toverhead /= 1000; /* convert to msec */ - toverhead /= 1000; /* convert to sec */ - -#ifdef MIRA_DEBUG - if (mira_debug > 3) { - uint32_t txtime; - txtime = ieee80211_mira_ht_txtime(mn->ampdu_size, ni->ni_txmcs, - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), sgi); - txtime += overhead - ieee80211_mira_ht_txtime(0, ni->ni_txmcs, - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), sgi); - DPRINTFN(4, ("txtime: %u usec\n", txtime)); - DPRINTFN(4, ("overhead: %u usec\n", overhead)); - DPRINTFN(4, ("toverhead: %s\n", mira_fp_sprintf(toverhead))); - } -#endif - return toverhead; -} - -void -ieee80211_mira_update_stats(struct ieee80211_mira_node *mn, - struct ieee80211com *ic, struct ieee80211_node *ni) -{ - /* Magic numbers from MiRA paper. */ - static const uint64_t alpha = MIRA_FP_1 / 8; /* 1/8 = 0.125 */ - static const uint64_t beta = MIRA_FP_1 / 4; /* 1/4 = 0.25 */ - uint64_t sfer, delta, toverhead; - uint64_t agglen = mn->agglen; - uint64_t ampdu_size = mn->ampdu_size * 8; /* convert to bits */ - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - uint64_t rate = ieee80211_mira_get_txrate(ni->ni_txmcs, sgi); - struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; - - if (mn->frames == 0) - return; /* avoid divide-by-zero in sfer calculation below */ - - g->nprobes += mn->agglen; - g->nprobe_bytes += mn->ampdu_size; - - ampdu_size <<= MIRA_FP_SHIFT; /* convert to fixed-point */ - agglen <<= MIRA_FP_SHIFT; - /* XXX range checks? */ - - ampdu_size = ampdu_size / 1000; /* kbit */ - ampdu_size = ampdu_size / 1000; /* mbit */ - - /* Compute Sub-Frame Error Rate (see section 2.2 in MiRA paper). */ - sfer = mn->frames * mn->txfail + mn->retries; - if ((sfer >> MIRA_FP_SHIFT) != 0) { /* bug in wifi driver */ - if (ic->ic_if.if_flags & IFF_DEBUG) { -#ifdef DIAGNOSTIC - printf("%s: mira sfer overflow\n", - ether_sprintf(ni->ni_macaddr)); -#endif -#ifdef MIRA_DEBUG - mira_print_driver_stats(mn, ni); -#endif - } - ieee80211_mira_probe_done(mn); - return; - } - sfer <<= MIRA_FP_SHIFT; /* convert to fixed-point */ - sfer /= (mn->txfail + 1) * mn->frames; - if (sfer > MIRA_FP_1) { /* bug in wifi driver */ - if (ic->ic_if.if_flags & IFF_DEBUG) { -#ifdef DIAGNOSTIC - printf("%s: mira sfer > 1\n", - ether_sprintf(ni->ni_macaddr)); -#endif -#ifdef MIRA_DEBUG - mira_print_driver_stats(mn, ni); -#endif - } - sfer = MIRA_FP_1; /* round down */ - } - - /* Store current loss percentage SFER. */ - g->loss = sfer * 100; -#ifdef MIRA_DEBUG - if (g->loss && ieee80211_mira_probe_valid(mn, ni)) - DPRINTFN(2, ("frame error rate at MCS %d: %s%%\n", - ni->ni_txmcs, mira_fp_sprintf(g->loss))); -#endif - - /* - * Update goodput statistics (see section 5.1.2 in MiRA paper). - * We use a slightly modified but equivalent calculation which - * is tuned towards our fixed-point number format. - */ - - g->average_agg = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average_agg); - g->average_agg += MIRA_FP_MUL(alpha, agglen); - - toverhead = ieee80211_mira_toverhead(mn, ic, ni); - toverhead = MIRA_FP_MUL(toverhead, rate); - g->measured = MIRA_FP_DIV(MIRA_FP_1 - sfer, MIRA_FP_1 + - MIRA_FP_DIV(toverhead, MIRA_FP_MUL(ampdu_size, g->average_agg))); - g->measured = MIRA_FP_MUL(g->measured, rate); - - g->average = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average); - g->average += MIRA_FP_MUL(alpha, g->measured); - - g->stddeviation = MIRA_FP_MUL(MIRA_FP_1 - beta, g->stddeviation); - if (g->average > g->measured) - delta = g->average - g->measured; - else - delta = g->measured - g->average; - g->stddeviation += MIRA_FP_MUL(beta, delta); -} - -void -ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *mn) -{ - int i; - - for (i = 0; i < nitems(mn->g); i++) { - struct ieee80211_mira_goodput_stats *g = &mn->g[i]; - memset(g, 0, sizeof(*g)); - g->average_agg = 1; - g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN; - } -} - -void -ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *mn) -{ - mn->frames = 0; - mn->retries = 0; - mn->txfail = 0; - mn->ampdu_size = 0; - mn->agglen = 1; -} - -/* - * Rate selection. - */ - -/* A rate's goodput has to be at least this much larger to be "better". */ -#define IEEE80211_MIRA_RATE_THRESHOLD (MIRA_FP_1 / 64) /* ~ 0.015 */ - -#define IEEE80211_MIRA_LOSS_THRESHOLD 10 /* in percent */ - -/* Number of (sub-)frames which render a probe valid. */ -#define IEEE80211_MIRA_MIN_PROBE_FRAMES 4 - -/* Number of bytes which, alternatively, render a probe valid. */ -#define IEEE80211_MIRA_MIN_PROBE_BYTES (2 * IEEE80211_MAX_LEN) - -/* Number of Tx failures which, alternatively, render a probe valid. */ -#define IEEE80211_MIRA_MAX_PROBE_TXFAIL 1 - -/* Number of Tx retries which, alternatively, render a probe valid. */ -#define IEEE80211_MIRA_MAX_PROBE_RETRIES 4 - -int -ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - const struct ieee80211_ht_rateset *rs; - int i, next; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - - rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi); - if (ni->ni_txmcs == rs->min_mcs) - return rs->min_mcs; - - next = ni->ni_txmcs; - for (i = rs->nrates - 1; i >= 0; i--) { - if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0) - continue; - if (i + rs->min_mcs < ni->ni_txmcs) { - next = i + rs->min_mcs; - break; - } - } - - return next; -} - -int -ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - const struct ieee80211_ht_rateset *rs; - int i, next; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - - rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi); - if (ni->ni_txmcs == rs->max_mcs) - return rs->max_mcs; - - next = ni->ni_txmcs; - for (i = 0; i < rs->nrates; i++) { - if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0) - continue; - if (i + rs->min_mcs > ni->ni_txmcs) { - next = i + rs->min_mcs; - break; - } - } - - return next; -} - -const struct ieee80211_ht_rateset * -ieee80211_mira_next_rateset(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - const struct ieee80211_ht_rateset *rs, *rsnext; - int next; - int mcs = ni->ni_txmcs; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - - rs = ieee80211_mira_get_rateset(mcs, sgi); - if (mn->probing & IEEE80211_MIRA_PROBING_UP) { - if (rs->max_mcs == 7) /* MCS 0-7 */ - next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI : - IEEE80211_HT_RATESET_MIMO2; - else if (rs->max_mcs == 15) /* MCS 8-15 */ - next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI : - IEEE80211_HT_RATESET_MIMO3; - else if (rs->max_mcs == 23) /* MCS 16-23 */ - next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI : - IEEE80211_HT_RATESET_MIMO4; - else /* MCS 24-31 */ - return NULL; - } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) { - if (rs->min_mcs == 24) /* MCS 24-31 */ - next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI : - IEEE80211_HT_RATESET_MIMO3; - else if (rs->min_mcs == 16) /* MCS 16-23 */ - next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI : - IEEE80211_HT_RATESET_MIMO2; - else if (rs->min_mcs == 8) /* MCS 8-15 */ - next = sgi ? IEEE80211_HT_RATESET_SISO_SGI : - IEEE80211_HT_RATESET_SISO; - else /* MCS 0-7 */ - return NULL; - } else - panic("%s: invalid probing mode %d", __func__, mn->probing); - - rsnext = &ieee80211_std_ratesets_11n[next]; - if ((rsnext->mcs_mask & mn->valid_rates) == 0) - return NULL; - - return rsnext; -} - -int -ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *mn, - const struct ieee80211_ht_rateset *rs) -{ - uint64_t gmax = 0; - int i, best_mcs = rs->min_mcs; - - for (i = 0; i < rs->nrates; i++) { - int mcs = rs->min_mcs + i; - struct ieee80211_mira_goodput_stats *g = &mn->g[mcs]; - if (((1 << mcs) & mn->valid_rates) == 0) - continue; - if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) { - gmax = g->measured; - best_mcs = mcs; - } - } - - return best_mcs; -} - -void -ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni, const struct ieee80211_ht_rateset *rsnext) -{ - const struct ieee80211_ht_rateset *rs; - struct ieee80211_mira_goodput_stats *g; - int best_mcs, i; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - - /* Find most recently measured best MCS from the current rateset. */ - rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi); - best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs); - - /* Switch to the next rateset. */ - ni->ni_txmcs = rsnext->min_mcs; - if ((mn->valid_rates & (1 << rsnext->min_mcs)) == 0) - ni->ni_txmcs = ieee80211_mira_next_intra_rate(mn, ni); - - /* Select the lowest rate from the next rateset with loss-free - * goodput close to the current best measurement. */ - g = &mn->g[best_mcs]; - for (i = 0; i < rsnext->nrates; i++) { - int mcs = rsnext->min_mcs + i; - uint64_t txrate = rsnext->rates[i]; - - if ((mn->valid_rates & (1 << mcs)) == 0) - continue; - - txrate = txrate * 500; /* convert to kbit/s */ - txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */ - txrate /= 1000; /* convert to mbit/s */ - - if (txrate > g->measured + IEEE80211_MIRA_RATE_THRESHOLD) { - ni->ni_txmcs = mcs; - break; - } - } - /* If all rates are lower the maximum rate is the closest match. */ - if (i == rsnext->nrates) - ni->ni_txmcs = rsnext->max_mcs; - - /* Add rates from the next rateset as candidates. */ - mn->candidate_rates |= (1 << ni->ni_txmcs); - if (mn->probing & IEEE80211_MIRA_PROBING_UP) { - mn->candidate_rates |= - (1 << ieee80211_mira_next_intra_rate(mn, ni)); - } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) { -#ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING - mn->candidate_rates |= ieee80211_mira_mcs_below(mn, - ni->ni_txmcs, sgi); -#else - mn->candidate_rates |= - (1 << ieee80211_mira_next_lower_intra_rate(mn, ni)); -#endif - } else - panic("%s: invalid probing mode %d", __func__, mn->probing); -} - -int -ieee80211_mira_next_mcs(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - int next; - - if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) - next = ieee80211_mira_next_lower_intra_rate(mn, ni); - else if (mn->probing & IEEE80211_MIRA_PROBING_UP) - next = ieee80211_mira_next_intra_rate(mn, ni); - else - panic("%s: invalid probing mode %d", __func__, mn->probing); - - return next; -} - -int -ieee80211_mira_prev_mcs(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - int next; - - if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) - next = ieee80211_mira_next_intra_rate(mn, ni); - else if (mn->probing & IEEE80211_MIRA_PROBING_UP) - next = ieee80211_mira_next_lower_intra_rate(mn, ni); - else - panic("%s: invalid probing mode %d", __func__, mn->probing); - - return next; -} - -int -ieee80211_mira_probe_valid(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; - - return (g->nprobes >= IEEE80211_MIRA_MIN_PROBE_FRAMES || - g->nprobe_bytes >= IEEE80211_MIRA_MIN_PROBE_BYTES || - mn->txfail >= IEEE80211_MIRA_MAX_PROBE_TXFAIL || - mn->retries >= IEEE80211_MIRA_MAX_PROBE_RETRIES); -} - -void -ieee80211_mira_probe_done(struct ieee80211_mira_node *mn) -{ - int mcs; - - /* Reset probe interval of the best rate. */ - mn->g[mn->best_mcs].probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN; - mn->g[mn->best_mcs].nprobes = 0; - mn->g[mn->best_mcs].nprobe_bytes = 0; - - /* Update probing interval of other probed rates. */ - for (mcs = 0; mcs < IEEE80211_HT_RATESET_NUM_MCS; mcs++) { - if (mcs != mn->best_mcs && (mn->probed_rates & (1 << mcs))) - ieee80211_mira_update_probe_interval(&mn->g[mcs]); - } - - ieee80211_mira_cancel_timeouts(mn); - ieee80211_mira_reset_driver_stats(mn); - ieee80211_mira_reset_collision_stats(mn); - mn->probing = IEEE80211_MIRA_NOT_PROBING; - mn->probed_rates = 0; - mn->candidate_rates = 0; -} - -int -ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - const struct ieee80211_ht_rateset *rs; - struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; - int next_mcs, best_mcs, probed_rates; - uint64_t next_rate; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - - if (!ieee80211_mira_probe_valid(mn, ni)) - return 0; - - probed_rates = (mn->probed_rates | (1 << ni->ni_txmcs)); - - /* Check if the min/max MCS in this rateset has been probed. */ - rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi); - if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) { - if (ni->ni_txmcs == rs->min_mcs || - probed_rates & (1 << rs->min_mcs)) { - ieee80211_mira_trigger_next_rateset(mn, ni); - return 1; - } - } else if (mn->probing & IEEE80211_MIRA_PROBING_UP) { - if (ni->ni_txmcs == rs->max_mcs || - probed_rates & (1 << rs->max_mcs)) { - ieee80211_mira_trigger_next_rateset(mn, ni); - return 1; - } - } - - /* - * Check if the measured goodput is loss-free and better than the - * loss-free goodput of the candidate rate. - */ - next_mcs = ieee80211_mira_next_mcs(mn, ni); - if (next_mcs == ni->ni_txmcs) { - ieee80211_mira_trigger_next_rateset(mn, ni); - return 1; - } - next_rate = ieee80211_mira_get_txrate(next_mcs, sgi); - if (g->loss == 0 && - g->measured >= next_rate + IEEE80211_MIRA_RATE_THRESHOLD) { - ieee80211_mira_trigger_next_rateset(mn, ni); - return 1; - } - - /* Check if we had a better measurement at a previously probed MCS. */ - best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs); - if (best_mcs != ni->ni_txmcs && (probed_rates & (1 << best_mcs))) { - if ((mn->probing & IEEE80211_MIRA_PROBING_UP) && - best_mcs < ni->ni_txmcs) { - ieee80211_mira_trigger_next_rateset(mn, ni); - return 1; - } - if ((mn->probing & IEEE80211_MIRA_PROBING_DOWN) && - best_mcs > ni->ni_txmcs) { - ieee80211_mira_trigger_next_rateset(mn, ni); - return 1; - } - } - - /* Check if all rates in the set of candidate rates have been probed. */ - if ((mn->candidate_rates & probed_rates) == mn->candidate_rates) { - /* Remain in the current rateset until above checks trigger. */ - return 1; - } - - return 0; -} - -void -ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - const struct ieee80211_ht_rateset *rsnext; - - rsnext = ieee80211_mira_next_rateset(mn, ni); - if (rsnext) { - ieee80211_mira_probe_next_rateset(mn, ni, rsnext); - mn->probing |= IEEE80211_MIRA_PROBING_INTER; - } else - mn->probing &= ~IEEE80211_MIRA_PROBING_INTER; -} - -int -ieee80211_mira_inter_mode_ra_finished(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - return ((mn->probing & IEEE80211_MIRA_PROBING_INTER) == 0); -} - -int -ieee80211_mira_best_rate(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - int i, best = 0; - uint64_t gmax = 0; - - for (i = 0; i < nitems(mn->g); i++) { - struct ieee80211_mira_goodput_stats *g = &mn->g[i]; - if (((1 << i) & mn->valid_rates) == 0) - continue; - if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) { - gmax = g->measured; - best = i; - } - } - -#ifdef MIRA_DEBUG - if (mn->best_mcs != best) { - DPRINTF(("MCS %d is best; MCS{Mbps|probe interval}:", best)); - for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { - struct ieee80211_mira_goodput_stats *g = &mn->g[i]; - if ((mn->valid_rates & (1 << i)) == 0) - continue; - DPRINTF((" %d{%s|%dms}", i, - mira_fp_sprintf(g->measured), - g->probe_interval)); - } - DPRINTF(("\n")); - } -#endif - return best; -} - -/* See section 5.1.1 (at "Adaptive probing interval") in MiRA paper. */ -void -ieee80211_mira_update_probe_interval(struct ieee80211_mira_goodput_stats *g) -{ - uint64_t lt; - int intval; - - lt = g->loss / IEEE80211_MIRA_LOSS_THRESHOLD; - if (lt < MIRA_FP_1) - lt = MIRA_FP_1; - lt >>= MIRA_FP_SHIFT; /* round to integer */ - - intval = (1 << g->nprobes); /* 2^nprobes */ - if (intval > IEEE80211_MIRA_PROBE_INTVAL_MAX) - intval = IEEE80211_MIRA_PROBE_INTVAL_MAX; - - g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN * intval * lt; -} - -void -ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - struct ieee80211_mira_goodput_stats *g; - struct timeout *to; - int mcs; - - mcs = ieee80211_mira_next_intra_rate(mn, ni); - to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP]; - g = &mn->g[mcs]; - if (mcs != ni->ni_txmcs && !timeout_pending(to) && - !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) { - timeout_add_msec(to, g->probe_interval); - DPRINTFN(3, ("start probing up for node %s at MCS %d in at " - "least %d msec\n", - ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval)); - } - - mcs = ieee80211_mira_next_lower_intra_rate(mn, ni); - to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN]; - g = &mn->g[mcs]; - if (mcs != ni->ni_txmcs && !timeout_pending(to) && - !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) { - timeout_add_msec(to, g->probe_interval); - DPRINTFN(3, ("start probing down for node %s at MCS %d in at " - "least %d msec\n", - ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval)); - } -} - -int -ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - int ret = 0, expired_timer = IEEE80211_MIRA_PROBE_TO_INVALID; - int mcs; - - if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] && - mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) { - if (arc4random_uniform(2)) - expired_timer = IEEE80211_MIRA_PROBE_TO_UP; - else - expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN; - } else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) - expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN; - else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) - expired_timer = IEEE80211_MIRA_PROBE_TO_UP; - - if (expired_timer != IEEE80211_MIRA_PROBE_TO_INVALID) - mn->probe_timer_expired[expired_timer] = 0; - - switch (expired_timer) { - case IEEE80211_MIRA_PROBE_TO_UP: - /* Do time-based upwards probing on next frame. */ - DPRINTFN(2, ("probe timer expired: probe upwards\n")); - mn->probing = IEEE80211_MIRA_PROBING_UP; - mcs = ieee80211_mira_next_intra_rate(mn, ni); - mn->candidate_rates = (1 << mcs); - ret = 1; - break; - case IEEE80211_MIRA_PROBE_TO_DOWN: - /* Do time-based downwards probing on next frame. */ - DPRINTFN(2, ("probe timer expired: probe downwards\n")); - mn->probing = IEEE80211_MIRA_PROBING_DOWN; - mcs = ieee80211_mira_next_lower_intra_rate(mn, ni); - mn->candidate_rates = (1 << mcs); - ret = 1; - break; - case IEEE80211_MIRA_PROBE_TO_INVALID: - default: - ret = 0; - break; - } - - return ret; -} - -void -ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *mn, - struct ieee80211_node *ni) -{ - /* Select the next rate to probe. */ - mn->probed_rates |= (1 << ni->ni_txmcs); - ni->ni_txmcs = ieee80211_mira_next_mcs(mn, ni); -} - -int -ieee80211_mira_valid_tx_mcs(struct ieee80211com *ic, int mcs) -{ - uint32_t ntxstreams = 1; - static const int max_mcs[] = { 7, 15, 23, 31 }; - - if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0) - return isset(ic->ic_sup_mcs, mcs); - - ntxstreams += ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2); - if (ntxstreams < 1 || ntxstreams > 4) - panic("invalid number of Tx streams: %u", ntxstreams); - return (mcs <= max_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs)); -} - -uint32_t -ieee80211_mira_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni) -{ - uint32_t valid_mcs = 0; - int i; - - for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { - if (!isset(ni->ni_rxmcs, i)) - continue; - if (!ieee80211_mira_valid_tx_mcs(ic, i)) - continue; - valid_mcs |= (1 << i); - } - - return valid_mcs; -} - -uint32_t -ieee80211_mira_mcs_below(struct ieee80211_mira_node *mn, int mcs, int sgi) -{ - const struct ieee80211_ht_rateset *rs; - uint32_t mcs_mask; - int i; - - rs = ieee80211_mira_get_rateset(mcs, sgi); - mcs_mask = (1 << rs->min_mcs); - for (i = rs->min_mcs + 1; i < mcs; i++) { - if ((mn->valid_rates & (1 << i)) == 0) - continue; - mcs_mask |= (1 << i); - } - - return mcs_mask; -} - -/* - * Constants involved in detecting suspected frame collisions. - * See section 5.2 of MiRA paper - */ -#define MIRA_COLLISION_LOSS_PERCENTAGE 10 /* from MiRA paper */ -#define MIRA_COLLISION_DETECTED 3 /* from MiRA paper */ - -/* - * XXX The paper's algorithm assumes aggregated frames. This is particularly - * important for the detection of consecutive frame collisions which indicate - * high competition for air time. Because we do not yet support Tx aggregation, - * we run the algorithm over the result of several frames instead. - * We also aggregate retries across all frames and act upon a percentage of - * retried frames, rather than acting on retries seen for one aggregated frame. - * - * The collision window size (number of frames sent) needs to be short to - * ensure our detection of consecutive collisions remains somewhat accurate. - * We really have no idea how much time passes between frames in the window! - * The good news is that users will only care about collision detection during - * a transmit burst anyway, and we have this case more or less covered. - */ -#define MIRA_COLLISION_MIN_FRAMES 6 /* XXX magic number */ -#define MIRA_COLLISION_RETRY_PERCENTAGE 60 /* XXX magic number */ - -/* Set RTS threshold based on suspected collision from other STAs. */ -void -ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *mn, - struct ieee80211com *ic, struct ieee80211_node *ni) -{ - uint16_t rtsthreshold = mn->rts_threshold; - uint32_t loss, retry; - - /* Update collision window stats. */ - mn->ifwnd_frames += mn->frames; - mn->ifwnd_retries += mn->retries; - mn->ifwnd_txfail += mn->txfail; - if (mn->ifwnd_frames < MIRA_COLLISION_MIN_FRAMES) - return; /* not enough frames yet */ - - /* Check whether the loss pattern indicates frame collisions. */ - loss = (mn->ifwnd_txfail * 100) / mn->ifwnd_frames; - retry = (mn->ifwnd_retries * 100) / mn->ifwnd_frames; - if (retry > MIRA_COLLISION_RETRY_PERCENTAGE && - loss < MIRA_COLLISION_LOSS_PERCENTAGE) { - if (mn->ifwnd == 0) { - /* First frame collision confirmed. */ - mn->ifwnd = MIRA_COLLISION_DETECTED; - } else if (mn->ifwnd == MIRA_COLLISION_DETECTED) { - /* Successive frame collision confirmed. Use RTS. */ - rtsthreshold = IEEE80211_RTS_DEFAULT; - } - } else { - if (mn->ifwnd > 0) - mn->ifwnd--; - if (mn->ifwnd == 0) - rtsthreshold = IEEE80211_RTS_MAX; - } - - mn->rts_threshold = rtsthreshold; - ieee80211_mira_reset_collision_stats(mn); -} - -int -ieee80211_mira_get_rts_threshold(struct ieee80211_mira_node *mn, - struct ieee80211com *ic, struct ieee80211_node *ni, size_t framelen) -{ - int rtsrate = ieee80211_min_basic_rate(ic); - uint64_t txtime, rtsoverhead; - /* Magic number from MiRA paper ("cost/benefit ratio"). */ - static const uint64_t k = MIRA_FP_1 + (MIRA_FP_1 / 2); /* 1.5 */ - - if (mn->probing || mn->rts_threshold >= IEEE80211_RTS_MAX) - return IEEE80211_RTS_MAX; - - /* Use RTS only if potential gains outweigh overhead. */ - txtime = ieee80211_mira_ht_txtime(framelen, ni->ni_txmcs, - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), - (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0); - rtsoverhead = ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rtsrate, ic); - rtsoverhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rtsrate, ic); - /* convert to fixed-point */ - txtime <<= MIRA_FP_SHIFT; - rtsoverhead <<= MIRA_FP_SHIFT; - if (txtime >= MIRA_FP_MUL(k, rtsoverhead)) - return mn->rts_threshold; - - return IEEE80211_RTS_MAX; -} - -void -ieee80211_mira_reset_collision_stats(struct ieee80211_mira_node *mn) -{ - mn->ifwnd_frames = 0; - mn->ifwnd_retries = 0; - mn->ifwnd_txfail = 0; -} - -void -ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com *ic, - struct ieee80211_node *ni) -{ - struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; - int s; - int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0; - const struct ieee80211_ht_rateset *rs; - - s = splnet(); - - if (mn->valid_rates == 0) - mn->valid_rates = ieee80211_mira_valid_rates(ic, ni); - -#ifdef MIRA_DEBUG - if (mira_debug >= 5) - mira_print_driver_stats(mn, ni); -#endif - ieee80211_mira_update_stats(mn, ic, ni); - - if (mn->probing) { - /* Probe another rate or settle at the best rate. */ - if (!ieee80211_mira_intra_mode_ra_finished(mn, ni)) { - if (ieee80211_mira_probe_valid(mn, ni)) { - ieee80211_mira_probe_next_rate(mn, ni); - ieee80211_mira_reset_driver_stats(mn); - } - DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs)); - } else if (ieee80211_mira_inter_mode_ra_finished(mn, ni)) { - mn->best_mcs = ieee80211_mira_best_rate(mn, ni); - ni->ni_txmcs = mn->best_mcs; - ieee80211_mira_probe_done(mn); - } - - splx(s); - return; - } else { - ieee80211_mira_set_rts_threshold(mn, ic, ni); - ieee80211_mira_reset_driver_stats(mn); - ieee80211_mira_schedule_probe_timers(mn, ni); - } - - if (ieee80211_mira_check_probe_timers(mn, ni)) { - /* Time-based probing has triggered. */ - splx(s); - return; - } - - /* Check if event-based probing should be triggered. */ - rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi); - if (g->measured < g->average - 2 * g->stddeviation && - ni->ni_txmcs != rs->min_mcs) { - /* Channel becomes bad. Probe downwards. */ - DPRINTFN(2, ("channel becomes bad; probe downwards\n")); - DPRINTFN(3, ("measured: %s Mbit/s\n", - mira_fp_sprintf(g->measured))); - DPRINTFN(3, ("average: %s Mbit/s\n", - mira_fp_sprintf(g->average))); - DPRINTFN(3, ("stddeviation: %s\n", - mira_fp_sprintf(g->stddeviation))); - mn->probing = IEEE80211_MIRA_PROBING_DOWN; - mn->probed_rates = 0; -#ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING - /* Allow for probing all the way down within this rateset. */ - mn->candidate_rates = ieee80211_mira_mcs_below(mn, - ni->ni_txmcs, sgi); -#else - /* Probe the lower candidate rate to see if it's any better. */ - mn->candidate_rates = - (1 << ieee80211_mira_next_lower_intra_rate(mn, ni)); -#endif - ieee80211_mira_cancel_timeouts(mn); - } else if (g->measured > g->average + 2 * g->stddeviation && - ni->ni_txmcs != rs->max_mcs) { - /* Channel becomes good. */ - DPRINTFN(2, ("channel becomes good; probe upwards\n")); - DPRINTFN(3, ("measured: %s Mbit/s\n", - mira_fp_sprintf(g->measured))); - DPRINTFN(3, ("average: %s Mbit/s\n", - mira_fp_sprintf(g->average))); - DPRINTFN(3, ("stddeviation: %s\n", - mira_fp_sprintf(g->stddeviation))); - mn->probing = IEEE80211_MIRA_PROBING_UP; - mn->probed_rates = 0; - /* Probe the upper candidate rate to see if it's any better. */ - mn->candidate_rates = - (1 << ieee80211_mira_next_intra_rate(mn, ni)); - ieee80211_mira_cancel_timeouts(mn); - } else { - /* Remain at current rate. */ - mn->probing = IEEE80211_MIRA_NOT_PROBING; - mn->probed_rates = 0; - mn->candidate_rates = 0; - } - - splx(s); -} - -void -ieee80211_mira_node_init(struct ieee80211_mira_node *mn) -{ - memset(mn, 0, sizeof(*mn)); - mn->agglen = 1; - mn->rts_threshold = IEEE80211_RTS_MAX; - ieee80211_mira_reset_goodput_stats(mn); - ieee80211_mira_reset_collision_stats(mn); - - timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP], - ieee80211_mira_probe_timeout_up, mn); - timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN], - ieee80211_mira_probe_timeout_down, mn); -} - -void -ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *mn) -{ - int t; - - for (t = 0; t < nitems(mn->probe_to); t++) - timeout_del(&mn->probe_to[t]); -} - -int -ieee80211_mira_is_probing(struct ieee80211_mira_node *mn) -{ - return mn->probing != IEEE80211_MIRA_NOT_PROBING; -} - -int -ieee80211_mira_get_best_mcs(struct ieee80211_mira_node *mn) -{ - return mn->best_mcs; -} diff --git a/sys/net80211/ieee80211_mira.h b/sys/net80211/ieee80211_mira.h deleted file mode 100644 index 00aed5cae09..00000000000 --- a/sys/net80211/ieee80211_mira.h +++ /dev/null @@ -1,121 +0,0 @@ -/* $OpenBSD: ieee80211_mira.h,v 1.8 2020/03/03 21:09:35 tb Exp $ */ - -/* - * Copyright (c) 2016 Stefan Sperling - * Copyright (c) 2016 Theo Buehler - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _NET80211_IEEE80211_MIRA_H_ -#define _NET80211_IEEE80211_MIRA_H_ - -/* - * MiRA - "MIMO Rate Adaptation in 802.11n Wireless Networks" - * Ioannis Pefkianakis, Yun Hu, Starsky H.Y. Wong, Hao Yang, Songwu Lu - * http://metro.cs.ucla.edu/papers/Pefkianakis.MOBICOM10.pdf - * https://doi.org/10.1145/1859995.1860025 - */ - -/* - * Goodput statistics struct. Measures the effective data rate of an MCS - * index and contains data related to time-based probing to a new rate. - * All uint64_t numbers in this struct use fixed-point arithmetic. - */ -struct ieee80211_mira_goodput_stats { - uint64_t measured; /* Most recently measured goodput. */ - uint64_t average; /* Average measured goodput. */ - uint64_t average_agg; /* Average number of subframes per frame. */ - uint64_t stddeviation; /* Goodput standard deviation. */ - - /* These fields are used while calculating probe intervals: */ - uint64_t loss; /* This rate's loss percentage SFER. */ - uint32_t nprobes; /* Number of probe attempts. */ - uint32_t nprobe_bytes; /* Number of bytes sent while probing. */ - int probe_interval; /* Probe interval for this rate. */ - int probe_timeout_triggered; /* It is time to probe this rate. */ -}; - -/* - * Rate control state. - */ -struct ieee80211_mira_node { - /* - * Fields set by drivers before calling ieee80211_mira_choose(). - */ - uint32_t frames; /* Increment per (sub-)frame transmitted. */ - uint32_t retries; /* Increment per Tx retry (MiRA "nbad") */ - uint32_t txfail; /* Increment per Tx failure (MiRA "retries") */ - uint32_t ampdu_size; /* Length of last (aggregated) frame sent. */ - uint32_t agglen; /* Number of subframes in last frame (1-64). */ - - /* - * Private fields for use by the rate control algorithm. - */ - - /* Bitmaps MCS 0-31. */ - uint32_t valid_rates; - uint32_t candidate_rates; - uint32_t probed_rates; - - /* Timeouts which trigger time-driven probing. */ - struct timeout probe_to[2]; -#define IEEE80211_MIRA_PROBE_TO_INVALID -1 -#define IEEE80211_MIRA_PROBE_TO_UP 0 -#define IEEE80211_MIRA_PROBE_TO_DOWN 1 - int probe_timer_expired[2]; - - /* Probing state. */ - int probing; -#define IEEE80211_MIRA_NOT_PROBING 0x0 -#define IEEE80211_MIRA_PROBING_DOWN 0x1 -#define IEEE80211_MIRA_PROBING_UP 0x2 -#define IEEE80211_MIRA_PROBING_INTER 0x4 /* combined with UP or DOWN */ - - /* The current best MCS found by probing. */ - int best_mcs; - - /* Goodput statistics for each MCS. */ - struct ieee80211_mira_goodput_stats g[IEEE80211_HT_RATESET_NUM_MCS]; - - /* Interference observation window (see MiRA paper section 5.2). */ - int ifwnd; - uint32_t ifwnd_frames; - uint32_t ifwnd_retries; - uint32_t ifwnd_txfail; - - /* Current RTS threshold for this node. */ - int rts_threshold; -}; - -/* Initialize rate control state. */ -void ieee80211_mira_node_init(struct ieee80211_mira_node *); - -/* Called by drivers from the Tx completion interrupt handler. */ -void ieee80211_mira_choose(struct ieee80211_mira_node *, - struct ieee80211com *, struct ieee80211_node *); - -/* Cancel timeouts scheduled by ieee80211_mira_choose(). */ -void ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *); - -/* Returns RTS threshold to be used for a frame about to be transmitted. */ -int ieee80211_mira_get_rts_threshold(struct ieee80211_mira_node *, - struct ieee80211com *, struct ieee80211_node *, size_t); - -/* Indicate whether Tx rates are currently being probed. */ -int ieee80211_mira_is_probing(struct ieee80211_mira_node *); - -/* Return the best MCS determined by the most recent probe. */ -int ieee80211_mira_get_best_mcs(struct ieee80211_mira_node *); - -#endif /* _NET80211_IEEE80211_MIRA_H_ */ -- 2.20.1