LCOV - code coverage report
Current view: top level - net80211 - ieee80211_mira.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 442 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ieee80211_mira.c,v 1.12 2018/07/11 21:18:23 nayden Exp $      */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2016 Stefan Sperling <stsp@openbsd.org>
       5             :  * Copyright (c) 2016 Theo Buehler <tb@openbsd.org>
       6             :  * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
       7             :  *
       8             :  * Permission to use, copy, modify, and distribute this software for any
       9             :  * purpose with or without fee is hereby granted, provided that the above
      10             :  * copyright notice and this permission notice appear in all copies.
      11             :  *
      12             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      13             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      14             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      15             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      16             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      17             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      18             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      19             :  */
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/socket.h>
      24             : 
      25             : #include <net/if.h>
      26             : #include <net/if_media.h>
      27             : 
      28             : #include <netinet/in.h>
      29             : #include <netinet/if_ether.h>
      30             : 
      31             : #include <net80211/ieee80211_var.h>
      32             : #include <net80211/ieee80211_mira.h>
      33             : 
      34             : /* Allow for aggressive down probing when channel quality changes. */
      35             : #define MIRA_AGGRESSIVE_DOWNWARDS_PROBING
      36             : 
      37             : const struct ieee80211_mira_rateset *   ieee80211_mira_get_rateset(int);
      38             : void    ieee80211_mira_probe_timeout_up(void *);
      39             : void    ieee80211_mira_probe_timeout_down(void *);
      40             : uint64_t ieee80211_mira_get_txrate(int);
      41             : uint16_t ieee80211_mira_legacy_txtime(uint32_t, int, struct ieee80211com *);
      42             : uint32_t ieee80211_mira_ht_txtime(uint32_t, int, int);
      43             : int     ieee80211_mira_best_basic_rate(struct ieee80211_node *);
      44             : int     ieee80211_mira_ack_rate(struct ieee80211_node *);
      45             : uint64_t ieee80211_mira_toverhead(struct ieee80211_mira_node *,
      46             :             struct ieee80211com *, struct ieee80211_node *);
      47             : void    ieee80211_mira_update_stats(struct ieee80211_mira_node *,
      48             :             struct ieee80211com *, struct ieee80211_node *);
      49             : void    ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *);
      50             : void    ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *);
      51             : int     ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *,
      52             :             struct ieee80211_node *);
      53             : int     ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *,
      54             :             struct ieee80211_node *);
      55             : const struct ieee80211_mira_rateset * ieee80211_mira_next_rateset(
      56             :                     struct ieee80211_mira_node *, int);
      57             : int     ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *,
      58             :             const struct ieee80211_mira_rateset *);
      59             : void    ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *,
      60             :             struct ieee80211_node *, const struct ieee80211_mira_rateset *);
      61             : int     ieee80211_mira_next_mcs(struct ieee80211_mira_node *,
      62             :             struct ieee80211_node *);
      63             : int     ieee80211_mira_prev_mcs(struct ieee80211_mira_node *,
      64             :             struct ieee80211_node *);
      65             : int     ieee80211_mira_probe_valid(struct ieee80211_mira_node *,
      66             :             struct ieee80211_node *);
      67             : void    ieee80211_mira_probe_done(struct ieee80211_mira_node *);
      68             : int     ieee80211_mira_intra_mode_ra_finished(
      69             :             struct ieee80211_mira_node *, struct ieee80211_node *);
      70             : void    ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn,
      71             :             struct ieee80211_node *);
      72             : int     ieee80211_mira_inter_mode_ra_finished(
      73             :             struct ieee80211_mira_node *, struct ieee80211_node *);
      74             : int     ieee80211_mira_best_rate(struct ieee80211_mira_node *,
      75             :             struct ieee80211_node *);
      76             : void    ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *,
      77             :             struct ieee80211_mira_goodput_stats *);
      78             : void    ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *,
      79             :             struct ieee80211_node *);
      80             : int     ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *,
      81             :             struct ieee80211_node *);
      82             : void    ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *,
      83             :             struct ieee80211_node *);
      84             : int     ieee80211_mira_valid_tx_mcs(struct ieee80211com *, int);
      85             : uint32_t ieee80211_mira_valid_rates(struct ieee80211com *,
      86             :             struct ieee80211_node *);
      87             : uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int);
      88             : 
      89             : /* We use fixed point arithmetic with 64 bit integers. */
      90             : #define MIRA_FP_SHIFT   21
      91             : #define MIRA_FP_INT(x)  (x ## ULL << MIRA_FP_SHIFT) /* the integer x */
      92             : #define MIRA_FP_1       MIRA_FP_INT(1)
      93             : 
      94             : /* Multiply two fixed point numbers. */
      95             : #define MIRA_FP_MUL(a, b) \
      96             :         (((a) * (b)) >> MIRA_FP_SHIFT)
      97             : 
      98             : /* Divide two fixed point numbers. */
      99             : #define MIRA_FP_DIV(a, b) \
     100             :         (b == 0 ? (uint64_t)-1 : (((a) << MIRA_FP_SHIFT) / (b)))
     101             : 
     102             : #ifdef MIRA_DEBUG
     103             : #define DPRINTF(x)      do { if (mira_debug > 0) printf x; } while (0)
     104             : #define DPRINTFN(n, x)  do { if (mira_debug >= (n)) printf x; } while (0)
     105             : int mira_debug = 0;
     106             : #else
     107             : #define DPRINTF(x)      do { ; } while (0)
     108             : #define DPRINTFN(n, x)  do { ; } while (0)
     109             : #endif
     110             : 
     111             : #ifdef MIRA_DEBUG
     112             : void
     113             : mira_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp)
     114             : {
     115             :         uint64_t tmp;
     116             : 
     117             :         /* integer part */
     118             :         *i = (fp >> MIRA_FP_SHIFT);
     119             : 
     120             :         /* fractional part */
     121             :         tmp = (fp & ((uint64_t)-1 >> (64 - MIRA_FP_SHIFT)));
     122             :         tmp *= 100;
     123             :         *f = (uint32_t)(tmp >> MIRA_FP_SHIFT);
     124             : }
     125             : 
     126             : char *
     127             : mira_fp_sprintf(uint64_t fp)
     128             : {
     129             :         uint32_t i, f;
     130             :         static char buf[64];
     131             :         int ret;
     132             : 
     133             :         mira_fixedp_split(&i, &f, fp);
     134             :         ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f);
     135             :         if (ret == -1 || ret >= sizeof(buf))
     136             :                 return "ERR";
     137             : 
     138             :         return buf;
     139             : }
     140             : 
     141             : void
     142             : mira_print_driver_stats(struct ieee80211_mira_node *mn,
     143             :     struct ieee80211_node *ni) {
     144             :         DPRINTF(("%s driver stats:\n", ether_sprintf(ni->ni_macaddr)));
     145             :         DPRINTF(("mn->frames = %u\n", mn->frames));
     146             :         DPRINTF(("mn->retries = %u\n", mn->retries));
     147             :         DPRINTF(("mn->txfail = %u\n", mn->txfail));
     148             :         DPRINTF(("mn->ampdu_size = %u\n", mn->ampdu_size));
     149             :         DPRINTF(("mn->agglen = %u\n", mn->agglen));
     150             : }
     151             : #endif /* MIRA_DEBUG */
     152             : 
     153             : /*
     154             :  * Rate tables.
     155             :  */
     156             : 
     157             : /* Index into ieee80211_mira_ratesets[] array. */
     158             : #define IEEE80211_MIRA_RATESET_SISO     0
     159             : #define IEEE80211_MIRA_RATESET_MIMO2    1
     160             : #define IEEE80211_MIRA_RATESET_MIMO3    2
     161             : #define IEEE80211_MIRA_RATESET_MIMO4    3
     162             : 
     163             : #define IEEE80211_MIRA_RATESET_MAX 8 /* Maximum number of rates in a rateset. */
     164             : struct ieee80211_mira_rateset {
     165             :         uint32_t nrates;
     166             :         uint32_t rates[IEEE80211_MIRA_RATESET_MAX];
     167             :         uint32_t mcs_mask;
     168             :         int min_mcs;
     169             :         int max_mcs;
     170             : } ieee80211_mira_ratesets[] = {
     171             : /* XXX We only support MCS 0-31, for now. */
     172             : #ifdef notyet
     173             :         /* Legacy rates on a 2GHz channel. */
     174             :         { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }, 0x0, -1, -1 },
     175             : 
     176             :         /* Legacy rates on a 5GHz channel. */
     177             :         { 8, { 12, 18, 24, 36, 48, 72, 96, 108 }, 0x0, -1, -1 },
     178             : #endif
     179             :         /* MCS 0-7, 20MHz channel, no SGI */
     180             :         { 8, { 13, 26, 39, 52, 78, 104, 117, 130 }, 0x000000ff, 0, 7 },
     181             : 
     182             :         /* MCS 8-15, 20MHz channel, no SGI */
     183             :         { 8, { 26, 52, 78, 104, 156, 208, 234, 260 }, 0x0000ff00, 8, 15 },
     184             : 
     185             :         /* MCS 16-23, 20MHz channel, no SGI */
     186             :         { 8, { 39, 78, 117, 156, 234, 312, 351, 390  }, 0x00ff0000, 16, 23 },
     187             : 
     188             :         /* MCS 24-31, 20MHz channel, no SGI */
     189             :         { 8, { 52, 104, 156, 208, 312, 416, 468, 520 }, 0xff000000, 24, 31 },
     190             : };
     191             : 
     192             : /* XXX We only support HT rates, for now. With legacy added, these differ. */
     193             : #define IEEE80211_MIRA_NUM_MCS  IEEE80211_MIRA_NUM_RATES
     194             : 
     195             : const struct ieee80211_mira_rateset *
     196           0 : ieee80211_mira_get_rateset(int mcs)
     197             : {
     198             :         const struct ieee80211_mira_rateset *rs;
     199             :         int i;
     200             : 
     201           0 :         for (i = 0; i < nitems(ieee80211_mira_ratesets); i++) {
     202           0 :                 rs = &ieee80211_mira_ratesets[i];
     203           0 :                 if (mcs >= rs->min_mcs && mcs <= rs->max_mcs)
     204           0 :                         return rs;
     205             :         }
     206             : 
     207           0 :         panic("MCS %d is not part of any rateset", mcs);
     208             : }
     209             : 
     210             : /*
     211             :  * Probe timers.
     212             :  */
     213             : 
     214             : /* Constants related to timeouts for time-driven rate probing. */
     215             : #define IEEE80211_MIRA_PROBE_TIMEOUT_MIN        2               /* in msec */
     216             : #define IEEE80211_MIRA_PROBE_INTVAL_MAX         (1 << 10) /* 2^10 */
     217             : 
     218             : void
     219           0 : ieee80211_mira_probe_timeout_up(void *arg)
     220             : {
     221           0 :         struct ieee80211_mira_node *mn = arg;
     222             :         int s;
     223             : 
     224           0 :         s = splnet();
     225           0 :         mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] = 1;
     226             :         DPRINTFN(3, ("probe up timeout fired\n"));
     227           0 :         splx(s);
     228           0 : }
     229             : 
     230             : void
     231           0 : ieee80211_mira_probe_timeout_down(void *arg)
     232             : {
     233           0 :         struct ieee80211_mira_node *mn = arg;
     234             :         int s;
     235             : 
     236           0 :         s = splnet();
     237           0 :         mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN] = 1;
     238             :         DPRINTFN(3, ("probe down timeout fired\n"));
     239           0 :         splx(s);
     240           0 : }
     241             : 
     242             : /*
     243             :  * Update goodput statistics.
     244             :  */
     245             : 
     246             : uint64_t
     247           0 : ieee80211_mira_get_txrate(int mcs)
     248             : {
     249             :         const struct ieee80211_mira_rateset *rs;
     250             :         uint64_t txrate;
     251             : 
     252           0 :         rs = ieee80211_mira_get_rateset(mcs);
     253           0 :         txrate = rs->rates[mcs - rs->min_mcs];
     254           0 :         txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */
     255           0 :         txrate *= 500; /* convert to kbit/s */
     256           0 :         txrate /= 1000; /* convert to mbit/s */
     257             : 
     258           0 :         return txrate;
     259             : }
     260             : 
     261             : /* Based on rt2661_txtime in the ral(4) driver. */
     262             : uint16_t
     263           0 : ieee80211_mira_legacy_txtime(uint32_t len, int rate, struct ieee80211com *ic)
     264             : {
     265             : #define MIRA_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
     266             :         uint16_t txtime;
     267             : 
     268           0 :         if (MIRA_RATE_IS_OFDM(rate)) {
     269             :                 /* IEEE Std 802.11g-2003, pp. 44 */
     270           0 :                 txtime = (8 + 4 * len + 3 + rate - 1) / rate;
     271           0 :                 txtime = 16 + 4 + 4 * txtime + 6;
     272           0 :         } else {
     273             :                 /* IEEE Std 802.11b-1999, pp. 28 */
     274           0 :                 txtime = (16 * len + rate - 1) / rate;
     275           0 :                 if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
     276           0 :                         txtime +=  72 + 24;
     277             :                 else
     278           0 :                         txtime += 144 + 48;
     279             :         }
     280           0 :         return txtime;
     281             : }
     282             : 
     283             : uint32_t
     284           0 : ieee80211_mira_ht_txtime(uint32_t len, int mcs, int is2ghz)
     285             : {
     286             :         const struct ieee80211_mira_rateset *rs;
     287             :         /* XXX These constants should be macros in ieee80211.h instead. */
     288             :         const uint32_t t_lstf = 8; /* usec legacy short training field */
     289             :         const uint32_t t_lltf = 8; /* usec legacy long training field */
     290             :         const uint32_t t_lsig = 4; /* usec legacy signal field */
     291             :         const uint32_t t_htstf = 4; /* usec HT short training field */
     292             :         const uint32_t t_ltstf = 4; /* usec HT long training field */
     293             :         const uint32_t t_htsig = 8; /* usec HT signal field */
     294             :         const uint32_t t_sym = 4; /* usec symbol interval */
     295             :         uint32_t n_sym, n_dbps;
     296             :         uint32_t t_plcp;
     297             :         uint32_t t_data;
     298             :         uint32_t txtime;
     299             : 
     300             :         /*
     301             :          * Calculate approximate frame Tx time in usec.
     302             :          * See 802.11-2012, 20.4.3 "TXTIME calculation" and
     303             :          * 20.3.11.1 "Equation (20-32)".
     304             :          * XXX Assumes a 20MHz channel, HT-mixed frame format, no STBC.
     305             :          */
     306             :         t_plcp = t_lstf + t_lltf + t_lsig + t_htstf + 4 * t_ltstf + t_htsig;
     307           0 :         rs = ieee80211_mira_get_rateset(mcs);
     308           0 :         n_dbps = rs->rates[mcs - rs->min_mcs] * 2;
     309           0 :         n_sym = ((8 * len + 16 + 6) / n_dbps); /* "Equation (20-32)" */
     310           0 :         t_data = t_sym * n_sym;
     311             : 
     312           0 :         txtime = t_plcp + t_data;
     313           0 :         if (is2ghz)
     314           0 :                 txtime += 6; /* aSignalExtension */
     315             : 
     316           0 :         return txtime;
     317             : }
     318             : 
     319             : int
     320           0 : ieee80211_mira_best_basic_rate(struct ieee80211_node *ni)
     321             : {
     322           0 :         struct ieee80211_rateset *rs = &ni->ni_rates;
     323             :         int i, best, rval;
     324             : 
     325             :         /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */
     326           0 :         best = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? 2 : 12;
     327             : 
     328           0 :         for (i = 0; i < rs->rs_nrates; i++) {
     329           0 :                 if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0)
     330             :                         continue;
     331           0 :                 rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL);
     332           0 :                 if (rval > best)
     333           0 :                         best = rval;
     334             :         }
     335             : 
     336           0 :         return best;
     337             : }
     338             : 
     339             : /* 
     340             :  * See 802.11-2012, 9.7.6.5 "Rate selection for control response frames".
     341             :  * XXX Does not support BlockAck.
     342             :  */
     343             : int
     344           0 : ieee80211_mira_ack_rate(struct ieee80211_node *ni)
     345             : {
     346             :         /* 
     347             :          * Assume the ACK was sent at a mandatory ERP OFDM rate.
     348             :          * In the worst case, the firmware has retried at non-HT rates,
     349             :          * so for MCS 0 assume we didn't actually send an OFDM frame
     350             :          * and ACKs arrived at a basic rate.
     351             :          */
     352           0 :         if (ni->ni_txmcs == 0)
     353           0 :                 return ieee80211_mira_best_basic_rate(ni);
     354           0 :         else if (ni->ni_txmcs == 1)
     355           0 :                 return 12;      /* 6 Mbit/s */
     356           0 :         else if (ni->ni_txmcs >= 2)
     357           0 :                 return 24;      /* 12 Mbit/s */
     358             :         else
     359           0 :                 return 48;      /* 24 Mbit/s */
     360           0 : }
     361             : 
     362             : uint64_t
     363           0 : ieee80211_mira_toverhead(struct ieee80211_mira_node *mn,
     364             :     struct ieee80211com *ic, struct ieee80211_node *ni)
     365             : {
     366             : /* XXX These should be macros in ieee80211.h. */
     367             : #define MIRA_RTSLEN IEEE80211_MIN_LEN
     368             : #define MIRA_CTSLEN (sizeof(struct ieee80211_frame_cts) + IEEE80211_CRC_LEN)
     369             :         uint32_t overhead;
     370             :         uint64_t toverhead;
     371             :         int rate, rts;
     372             :         enum ieee80211_htprot htprot;
     373             : 
     374           0 :         overhead = ieee80211_mira_ht_txtime(0, ni->ni_txmcs,
     375           0 :             IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
     376             : 
     377           0 :         htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
     378           0 :         if (htprot == IEEE80211_HTPROT_NONMEMBER ||
     379           0 :             htprot == IEEE80211_HTPROT_NONHT_MIXED)
     380           0 :                 rts = 1;
     381           0 :         else if (htprot == IEEE80211_HTPROT_20MHZ &&
     382           0 :                 (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40))
     383           0 :                 rts = 1;
     384             :         else
     385           0 :                 rts = (mn->ampdu_size > ic->ic_rtsthreshold);
     386             : 
     387           0 :         if (rts) {
     388             :                 /* Assume RTS/CTS were sent at a basic rate. */
     389           0 :                 rate = ieee80211_mira_best_basic_rate(ni);
     390           0 :                 overhead += ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rate, ic);
     391           0 :                 overhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rate, ic);
     392           0 :         }
     393             : 
     394             :         /* XXX This does not yet support BlockAck. */
     395           0 :         rate = ieee80211_mira_ack_rate(ni);
     396           0 :         overhead += ieee80211_mira_legacy_txtime(IEEE80211_ACK_LEN, rate, ic);
     397             : 
     398           0 :         toverhead = overhead;
     399           0 :         toverhead <<= MIRA_FP_SHIFT; /* convert to fixed-point */
     400           0 :         toverhead /= 1000; /* convert to msec */
     401           0 :         toverhead /= 1000; /* convert to sec */
     402             : 
     403             : #ifdef MIRA_DEBUG
     404             :         if (mira_debug > 3) {
     405             :                 uint32_t txtime;
     406             :                 txtime = ieee80211_mira_ht_txtime(mn->ampdu_size, ni->ni_txmcs,
     407             :                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
     408             :                 txtime += overhead - ieee80211_mira_ht_txtime(0, ni->ni_txmcs,
     409             :                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
     410             :                 DPRINTFN(4, ("txtime: %u usec\n", txtime));
     411             :                 DPRINTFN(4, ("overhead: %u usec\n", overhead));
     412             :                 DPRINTFN(4, ("toverhead: %s\n", mira_fp_sprintf(toverhead)));
     413             :         }
     414             : #endif
     415           0 :         return toverhead;
     416             : }
     417             : 
     418             : void
     419           0 : ieee80211_mira_update_stats(struct ieee80211_mira_node *mn,
     420             :     struct ieee80211com *ic, struct ieee80211_node *ni)
     421             : {
     422             :         /* Magic numbers from MiRA paper. */
     423             :         static const uint64_t alpha = MIRA_FP_1 / 8; /* 1/8 = 0.125 */
     424             :         static const uint64_t beta =  MIRA_FP_1 / 4; /* 1/4 = 0.25 */
     425             :         uint64_t sfer, delta, toverhead;
     426           0 :         uint64_t agglen = mn->agglen;
     427           0 :         uint64_t ampdu_size = mn->ampdu_size * 8; /* convert to bits */
     428           0 :         uint64_t rate = ieee80211_mira_get_txrate(ni->ni_txmcs);
     429           0 :         struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
     430             : 
     431           0 :         g->nprobes += mn->agglen;
     432           0 :         g->nprobe_bytes += mn->ampdu_size;
     433             : 
     434           0 :         ampdu_size <<= MIRA_FP_SHIFT; /* convert to fixed-point */
     435           0 :         agglen <<= MIRA_FP_SHIFT;
     436             :         /* XXX range checks? */
     437             : 
     438           0 :         ampdu_size = ampdu_size / 1000; /* kbit */
     439           0 :         ampdu_size = ampdu_size / 1000; /* mbit */
     440             : 
     441             :         /* Compute Sub-Frame Error Rate (see section 2.2 in MiRA paper). */
     442           0 :         sfer = (mn->frames * mn->retries + mn->txfail);
     443           0 :         if ((sfer >> MIRA_FP_SHIFT) != 0) { /* bug in wifi driver */
     444           0 :                 if (ic->ic_if.if_flags & IFF_DEBUG) {
     445             : #ifdef DIAGNOSTIC
     446           0 :                         printf("%s: mira sfer overflow\n",
     447           0 :                             ether_sprintf(ni->ni_macaddr));
     448             : #endif
     449             : #ifdef MIRA_DEBUG
     450             :                         mira_print_driver_stats(mn, ni);
     451             : #endif
     452           0 :                 }
     453           0 :                 ieee80211_mira_probe_done(mn);
     454           0 :                 return;
     455             :         }
     456           0 :         sfer <<= MIRA_FP_SHIFT; /* convert to fixed-point */
     457           0 :         sfer /= ((mn->retries + 1) * mn->frames);
     458           0 :         if (sfer > MIRA_FP_1) { /* bug in wifi driver */
     459           0 :                 if (ic->ic_if.if_flags & IFF_DEBUG) {
     460             : #ifdef DIAGNOSTIC
     461           0 :                         printf("%s: mira sfer > 1\n",
     462           0 :                             ether_sprintf(ni->ni_macaddr));
     463             : #endif
     464             : #ifdef MIRA_DEBUG
     465             :                         mira_print_driver_stats(mn, ni);
     466             : #endif
     467           0 :                 }
     468             :                 sfer = MIRA_FP_1; /* round down */
     469           0 :         }
     470             : 
     471             :         /* Store current loss percentage SFER. */
     472           0 :         g->loss = sfer * 100;
     473             : #ifdef MIRA_DEBUG
     474             :         if (g->loss && ieee80211_mira_probe_valid(mn, ni))
     475             :                 DPRINTFN(2, ("frame error rate at MCS %d: %s%%\n",
     476             :                     ni->ni_txmcs, mira_fp_sprintf(g->loss)));
     477             : #endif
     478             : 
     479             :         /*
     480             :          * Update goodput statistics (see section 5.1.2 in MiRA paper).
     481             :          * We use a slightly modified but equivalent calculation which
     482             :          * is tuned towards our fixed-point number format.
     483             :          */
     484             : 
     485           0 :         g->average = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average);
     486           0 :         g->average += MIRA_FP_MUL(alpha, g->measured);
     487             : 
     488           0 :         g->stddeviation = MIRA_FP_MUL(MIRA_FP_1 - beta, g->stddeviation);
     489           0 :         if (g->average > g->measured)
     490           0 :                 delta = g->average - g->measured;
     491             :         else
     492           0 :                 delta = g->measured - g->average;
     493           0 :         g->stddeviation += MIRA_FP_MUL(beta, delta);
     494             : 
     495           0 :         g->average_agg = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average_agg);
     496           0 :         g->average_agg += MIRA_FP_MUL(alpha, agglen);
     497             : 
     498           0 :         toverhead = ieee80211_mira_toverhead(mn, ic, ni);
     499           0 :         toverhead = MIRA_FP_MUL(toverhead, rate);
     500           0 :         g->measured = MIRA_FP_DIV(MIRA_FP_1 - sfer, MIRA_FP_1 +
     501             :             MIRA_FP_DIV(toverhead, MIRA_FP_MUL(ampdu_size, g->average_agg)));
     502           0 :         g->measured = MIRA_FP_MUL(g->measured, rate);
     503           0 : }
     504             : 
     505             : void
     506           0 : ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *mn)
     507             : {
     508             :         int i;
     509             : 
     510           0 :         for (i = 0; i < nitems(mn->g); i++) {
     511           0 :                 struct ieee80211_mira_goodput_stats *g = &mn->g[i];
     512           0 :                 memset(g, 0, sizeof(*g));
     513           0 :                 g->average_agg = 1;
     514           0 :                 g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
     515             :         }
     516           0 : }
     517             : 
     518             : void
     519           0 : ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *mn)
     520             : {
     521           0 :         mn->frames = 0;
     522           0 :         mn->retries = 0;
     523           0 :         mn->txfail = 0;
     524           0 :         mn->ampdu_size = 0;
     525           0 :         mn->agglen = 1;
     526           0 : }
     527             : 
     528             : /*
     529             :  * Rate selection.
     530             :  */
     531             : 
     532             : /* A rate's goodput has to be at least this much larger to be "better". */
     533             : #define IEEE80211_MIRA_RATE_THRESHOLD   (MIRA_FP_1 / 64) /* ~ 0.015 */
     534             : 
     535             : #define IEEE80211_MIRA_LOSS_THRESHOLD   10      /* in percent */
     536             : 
     537             : /* Number of (sub-)frames which render a probe valid. */
     538             : #define IEEE80211_MIRA_MIN_PROBE_FRAMES 4
     539             : 
     540             : /* Number of bytes which, alternatively, render a probe valid. */
     541             : #define IEEE80211_MIRA_MIN_PROBE_BYTES IEEE80211_MAX_LEN
     542             : 
     543             : int
     544           0 : ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *mn,
     545             :     struct ieee80211_node *ni)
     546             : {
     547             :         const struct ieee80211_mira_rateset *rs;
     548             :         int i, next;
     549             : 
     550           0 :         rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
     551           0 :         if (ni->ni_txmcs == rs->min_mcs)
     552           0 :                 return rs->min_mcs;
     553             : 
     554             :         next = ni->ni_txmcs;
     555           0 :         for (i = rs->nrates - 1; i >= 0; i--) {
     556           0 :                 if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
     557             :                         continue;
     558           0 :                 if (i + rs->min_mcs < ni->ni_txmcs) {
     559             :                         next = i + rs->min_mcs;
     560           0 :                         break;
     561             :                 }
     562             :         }
     563             : 
     564           0 :         return next;
     565           0 : }
     566             : 
     567             : int
     568           0 : ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *mn,
     569             :     struct ieee80211_node *ni)
     570             : {
     571             :         const struct ieee80211_mira_rateset *rs;
     572             :         int i, next;
     573             : 
     574           0 :         rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
     575           0 :         if (ni->ni_txmcs == rs->max_mcs)
     576           0 :                 return rs->max_mcs;
     577             : 
     578             :         next = ni->ni_txmcs;
     579           0 :         for (i = 0; i < rs->nrates; i++) {
     580           0 :                 if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
     581             :                         continue;
     582           0 :                 if (i + rs->min_mcs > ni->ni_txmcs) {
     583             :                         next = i + rs->min_mcs;
     584           0 :                         break;
     585             :                 }
     586             :         }
     587             : 
     588           0 :         return next;
     589           0 : }
     590             : 
     591             : const struct ieee80211_mira_rateset *
     592           0 : ieee80211_mira_next_rateset(struct ieee80211_mira_node *mn, int mcs)
     593             : {
     594             :         const struct ieee80211_mira_rateset *rs, *rsnext;
     595             :         int next;
     596             : 
     597           0 :         rs = ieee80211_mira_get_rateset(mcs);
     598           0 :         if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
     599           0 :                 if (rs->max_mcs == 7)        /* MCS 0-7 */
     600           0 :                         next = IEEE80211_MIRA_RATESET_MIMO2;
     601           0 :                 else if (rs->max_mcs == 15)  /* MCS 8-15 */
     602           0 :                         next = IEEE80211_MIRA_RATESET_MIMO3;
     603           0 :                 else if (rs->max_mcs == 23)  /* MCS 16-23 */
     604             :                         next = IEEE80211_MIRA_RATESET_MIMO4;
     605             :                 else                            /* MCS 24-31 */
     606           0 :                         return NULL;
     607           0 :         } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
     608           0 :                 if (rs->min_mcs == 24)       /* MCS 24-31 */
     609           0 :                         next = IEEE80211_MIRA_RATESET_MIMO3;
     610           0 :                 else if (rs->min_mcs == 16)  /* MCS 16-23 */
     611           0 :                         next = IEEE80211_MIRA_RATESET_MIMO2;
     612           0 :                 else if (rs->min_mcs == 8)   /* MCS 8-15 */
     613             :                         next = IEEE80211_MIRA_RATESET_SISO;
     614             :                 else                            /* MCS 0-7 */
     615           0 :                         return NULL;
     616             :         } else
     617           0 :                 panic("%s: invalid probing mode %d", __func__, mn->probing);
     618             : 
     619           0 :         rsnext = &ieee80211_mira_ratesets[next];
     620           0 :         if ((rsnext->mcs_mask & mn->valid_rates) == 0)
     621           0 :                 return NULL;
     622             : 
     623           0 :         return rsnext;
     624           0 : }
     625             : 
     626             : int
     627           0 : ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *mn,
     628             :     const struct ieee80211_mira_rateset *rs)
     629             : {
     630             :         uint64_t gmax = 0;
     631           0 :         int i, best_mcs = rs->min_mcs;
     632             : 
     633           0 :         for (i = 0; i < rs->nrates; i++) {
     634           0 :                 int mcs = rs->min_mcs + i;
     635           0 :                 struct ieee80211_mira_goodput_stats *g = &mn->g[mcs];
     636           0 :                 if (((1 << mcs) & mn->valid_rates) == 0)
     637           0 :                         continue;
     638           0 :                 if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) {
     639             :                         gmax = g->measured;
     640             :                         best_mcs = mcs;
     641           0 :                 }
     642           0 :         }
     643             : 
     644           0 :         return best_mcs;
     645             : }
     646             :     
     647             : void
     648           0 : ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *mn,
     649             :     struct ieee80211_node *ni, const struct ieee80211_mira_rateset *rsnext)
     650             : {
     651             :         const struct ieee80211_mira_rateset *rs;
     652             :         struct ieee80211_mira_goodput_stats *g;
     653             :         int best_mcs, i;
     654             : 
     655             :         /* Find most recently measured best MCS from the current rateset. */
     656           0 :         rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
     657           0 :         best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs);
     658             : 
     659             :         /* Switch to the next rateset. */
     660           0 :         ni->ni_txmcs = rsnext->min_mcs;
     661           0 :         if ((mn->valid_rates & (1 << rsnext->min_mcs)) == 0)
     662           0 :                 ni->ni_txmcs = ieee80211_mira_next_intra_rate(mn, ni);
     663             : 
     664             :         /* Select the lowest rate from the next rateset with loss-free
     665             :          * goodput close to the current best measurement. */
     666           0 :         g = &mn->g[best_mcs];
     667           0 :         for (i = 0; i < rsnext->nrates; i++) {
     668           0 :                 int mcs = rsnext->min_mcs + i;
     669           0 :                 uint64_t txrate = rsnext->rates[i];
     670             : 
     671           0 :                 if ((mn->valid_rates & (1 << mcs)) == 0)
     672           0 :                         continue;
     673             : 
     674           0 :                 txrate = txrate * 500; /* convert to kbit/s */
     675           0 :                 txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */
     676           0 :                 txrate /= 1000; /* convert to mbit/s */
     677             : 
     678           0 :                 if (txrate > g->measured + IEEE80211_MIRA_RATE_THRESHOLD) {
     679           0 :                         ni->ni_txmcs = mcs;
     680           0 :                         break;
     681             :                 }
     682           0 :         }
     683             : 
     684             :         /* Add rates from the next rateset as candidates. */
     685           0 :         mn->candidate_rates |= (1 << ni->ni_txmcs);
     686           0 :         if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
     687           0 :                 mn->candidate_rates |=
     688           0 :                   (1 << ieee80211_mira_next_intra_rate(mn, ni));
     689           0 :         } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
     690             : #ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
     691           0 :                 mn->candidate_rates |= ieee80211_mira_mcs_below(mn,
     692           0 :                     ni->ni_txmcs);
     693             : #else
     694             :                 mn->candidate_rates |=
     695             :                     (1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
     696             : #endif
     697             :         } else
     698           0 :                 panic("%s: invalid probing mode %d", __func__, mn->probing);
     699           0 : }
     700             : 
     701             : int
     702           0 : ieee80211_mira_next_mcs(struct ieee80211_mira_node *mn,
     703             :     struct ieee80211_node *ni)
     704             : {
     705             :         int next;
     706             : 
     707           0 :         if (mn->probing & IEEE80211_MIRA_PROBING_DOWN)
     708           0 :                 next = ieee80211_mira_next_lower_intra_rate(mn, ni);
     709           0 :         else if (mn->probing & IEEE80211_MIRA_PROBING_UP)
     710           0 :                 next = ieee80211_mira_next_intra_rate(mn, ni);
     711             :         else
     712           0 :                 panic("%s: invalid probing mode %d", __func__, mn->probing);
     713             : 
     714           0 :         return next;
     715             : }
     716             : 
     717             : int
     718           0 : ieee80211_mira_prev_mcs(struct ieee80211_mira_node *mn,
     719             :     struct ieee80211_node *ni)
     720             : {
     721             :         int next;
     722             : 
     723           0 :         if (mn->probing & IEEE80211_MIRA_PROBING_DOWN)
     724           0 :                 next = ieee80211_mira_next_intra_rate(mn, ni);
     725           0 :         else if (mn->probing & IEEE80211_MIRA_PROBING_UP)
     726           0 :                 next = ieee80211_mira_next_lower_intra_rate(mn, ni);
     727             :         else
     728           0 :                 panic("%s: invalid probing mode %d", __func__, mn->probing);
     729             : 
     730           0 :         return next;
     731             : }
     732             : 
     733             : int
     734           0 : ieee80211_mira_probe_valid(struct ieee80211_mira_node *mn,
     735             :     struct ieee80211_node *ni)
     736             : {
     737           0 :         struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
     738             : 
     739           0 :         return (g->nprobes >= IEEE80211_MIRA_MIN_PROBE_FRAMES ||
     740           0 :             g->nprobe_bytes >= IEEE80211_MIRA_MIN_PROBE_BYTES);
     741             : }
     742             : 
     743             : void
     744           0 : ieee80211_mira_probe_done(struct ieee80211_mira_node *mn)
     745             : {
     746           0 :         ieee80211_mira_cancel_timeouts(mn);
     747           0 :         ieee80211_mira_reset_driver_stats(mn);
     748           0 :         mn->probing = IEEE80211_MIRA_NOT_PROBING;
     749           0 :         mn->probed_rates = 0;
     750           0 :         mn->candidate_rates = 0;
     751           0 : }
     752             : 
     753             : int
     754           0 : ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *mn,
     755             :     struct ieee80211_node *ni)
     756             : {
     757             :         const struct ieee80211_mira_rateset *rs;
     758           0 :         struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
     759             :         int next_mcs, best_mcs, probed_rates;
     760             :         uint64_t next_rate;
     761             : 
     762           0 :         if (!ieee80211_mira_probe_valid(mn, ni))
     763           0 :                 return 0;
     764             : 
     765           0 :         probed_rates = (mn->probed_rates | (1 << ni->ni_txmcs));
     766             : 
     767             :         /* Check if the min/max MCS in this rateset has been probed. */
     768           0 :         rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
     769           0 :         if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
     770           0 :                 if (ni->ni_txmcs == rs->min_mcs ||
     771           0 :                     probed_rates & (1 << rs->min_mcs)) {
     772           0 :                         ieee80211_mira_trigger_next_rateset(mn, ni);
     773           0 :                         return 1;
     774             :                 }
     775           0 :         } else if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
     776           0 :                 if (ni->ni_txmcs == rs->max_mcs ||
     777           0 :                     probed_rates & (1 << rs->max_mcs)) {
     778           0 :                         ieee80211_mira_trigger_next_rateset(mn, ni);
     779           0 :                         return 1;
     780             :                 }
     781             :         }
     782             : 
     783             :         /*
     784             :          * Check if the measured goodput is better than the
     785             :          * loss-free goodput of the candidate rate.
     786             :          */
     787           0 :         next_mcs = ieee80211_mira_next_mcs(mn, ni);
     788           0 :         if (next_mcs == ni->ni_txmcs) {
     789           0 :                 ieee80211_mira_trigger_next_rateset(mn, ni);
     790           0 :                 return 1;
     791             :         }
     792           0 :         next_rate = ieee80211_mira_get_txrate(next_mcs);
     793           0 :         if (g->measured >= next_rate + IEEE80211_MIRA_RATE_THRESHOLD) {
     794           0 :                 ieee80211_mira_trigger_next_rateset(mn, ni);
     795           0 :                 return 1;
     796             :         }
     797             : 
     798             :         /* Check if we had a better measurement at a previously probed MCS. */
     799           0 :         best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs);
     800           0 :         if ((mn->probed_rates & (1 << best_mcs))) {
     801           0 :                 if ((mn->probing & IEEE80211_MIRA_PROBING_UP) &&
     802           0 :                     best_mcs < ni->ni_txmcs) {
     803           0 :                         ieee80211_mira_trigger_next_rateset(mn, ni);
     804           0 :                         return 1;
     805             :                 }
     806           0 :                 if ((mn->probing & IEEE80211_MIRA_PROBING_DOWN) &&
     807           0 :                     best_mcs > ni->ni_txmcs) {
     808           0 :                         ieee80211_mira_trigger_next_rateset(mn, ni);
     809           0 :                         return 1;
     810             :                 }
     811             :         }
     812             : 
     813             :         /* Check if all rates in the set of candidate rates have been probed. */
     814           0 :         if ((mn->candidate_rates & probed_rates) == mn->candidate_rates) {
     815             :                 /* Remain in the current rateset until above checks trigger. */
     816           0 :                 return 1;
     817             :         }
     818             : 
     819           0 :         return 0;
     820           0 : }
     821             : 
     822             : void
     823           0 : ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn,
     824             :     struct ieee80211_node *ni)
     825             : {
     826             :         const struct ieee80211_mira_rateset *rsnext;
     827             : 
     828           0 :         rsnext = ieee80211_mira_next_rateset(mn, ni->ni_txmcs);
     829           0 :         if (rsnext) {
     830           0 :                 ieee80211_mira_probe_next_rateset(mn, ni, rsnext);
     831           0 :                 mn->probing |= IEEE80211_MIRA_PROBING_INTER;
     832           0 :         } else
     833           0 :                 mn->probing &= ~IEEE80211_MIRA_PROBING_INTER;
     834           0 : }
     835             : 
     836             : int
     837           0 : ieee80211_mira_inter_mode_ra_finished(struct ieee80211_mira_node *mn,
     838             :     struct ieee80211_node *ni)
     839             : {
     840           0 :         return ((mn->probing & IEEE80211_MIRA_PROBING_INTER) == 0);
     841             : }
     842             : 
     843             : int
     844           0 : ieee80211_mira_best_rate(struct ieee80211_mira_node *mn,
     845             :     struct ieee80211_node *ni)
     846             : {
     847             :         int i, best = 0;
     848             :         uint64_t gmax = 0;
     849             : 
     850           0 :         for (i = 0; i < nitems(mn->g); i++) {
     851           0 :                 struct ieee80211_mira_goodput_stats *g = &mn->g[i];
     852           0 :                 if (((1 << i) & mn->valid_rates) == 0)
     853           0 :                         continue;
     854           0 :                 if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) {
     855             :                         gmax = g->measured;
     856             :                         best = i;
     857           0 :                 }
     858           0 :         }
     859             : 
     860             : #ifdef MIRA_DEBUG
     861             :         if (mn->best_mcs != best) {
     862             :                 DPRINTF(("MCS %d is best; MCS{Mbps|probe interval}:", best));
     863             :                 for (i = 0; i < IEEE80211_MIRA_NUM_MCS; i++) {
     864             :                         struct ieee80211_mira_goodput_stats *g = &mn->g[i];
     865             :                         if ((mn->valid_rates & (1 << i)) == 0)
     866             :                                 continue;
     867             :                         DPRINTF((" %d{%s|%dms}", i,
     868             :                             mira_fp_sprintf(g->measured),
     869             :                             g->probe_interval));
     870             :                 }
     871             :                 DPRINTF(("\n"));
     872             :         }
     873             : #endif
     874           0 :         return best;
     875             : }
     876             : 
     877             : /* See section 5.1.1 (at "Adaptive probing interval") in MiRA paper. */
     878             : void
     879           0 : ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *mn,
     880             :     struct ieee80211_mira_goodput_stats *g)
     881             : {
     882             :         uint64_t lt;
     883             :         int intval;
     884             : 
     885           0 :         lt = g->loss / IEEE80211_MIRA_LOSS_THRESHOLD;
     886           0 :         if (lt < MIRA_FP_1)
     887             :                 lt = MIRA_FP_1;
     888           0 :         lt >>= MIRA_FP_SHIFT; /* round to integer */
     889             : 
     890           0 :         intval = (1 << g->nprobes); /* 2^nprobes */
     891           0 :         if (intval > IEEE80211_MIRA_PROBE_INTVAL_MAX)
     892             :                 intval = IEEE80211_MIRA_PROBE_INTVAL_MAX;
     893             : 
     894           0 :         g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN * intval * lt;
     895           0 : }
     896             : 
     897             : void
     898           0 : ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *mn,
     899             :     struct ieee80211_node *ni)
     900             : {
     901             :         struct ieee80211_mira_goodput_stats *g;
     902             :         struct timeout *to;
     903             :         int mcs;
     904             : 
     905           0 :         mcs = ieee80211_mira_next_intra_rate(mn, ni);
     906           0 :         to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP];
     907           0 :         g = &mn->g[mcs];
     908           0 :         if (mcs != ni->ni_txmcs && !timeout_pending(to) &&
     909           0 :             !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) {
     910           0 :                 timeout_add_msec(to, g->probe_interval);
     911             :                 DPRINTFN(3, ("start probing up for node %s at MCS %d in at "
     912             :                     "least %d msec\n",
     913             :                     ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval));
     914           0 :         }
     915             : 
     916           0 :         mcs = ieee80211_mira_next_lower_intra_rate(mn, ni);
     917           0 :         to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN];
     918           0 :         g = &mn->g[mcs];
     919           0 :         if (mcs != ni->ni_txmcs && !timeout_pending(to) &&
     920           0 :             !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) {
     921           0 :                 timeout_add_msec(to, g->probe_interval);
     922             :                 DPRINTFN(3, ("start probing down for node %s at MCS %d in at "
     923             :                     "least %d msec\n",
     924             :                     ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval));
     925           0 :         }
     926           0 : }
     927             : 
     928             : int
     929           0 : ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *mn,
     930             :     struct ieee80211_node *ni)
     931             : {
     932             :         int ret = 0, expired_timer = IEEE80211_MIRA_PROBE_TO_INVALID;
     933             :         int mcs;
     934             : 
     935           0 :         if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] &&
     936           0 :             mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) {
     937           0 :                 if (arc4random_uniform(2))
     938           0 :                         expired_timer = IEEE80211_MIRA_PROBE_TO_UP;
     939             :                 else
     940             :                         expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN;
     941           0 :         } else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN])
     942           0 :                 expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN;
     943           0 :         else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP])
     944           0 :                 expired_timer = IEEE80211_MIRA_PROBE_TO_UP;
     945             : 
     946           0 :         if (expired_timer != IEEE80211_MIRA_PROBE_TO_INVALID)
     947           0 :                 mn->probe_timer_expired[expired_timer] = 0;
     948             : 
     949           0 :         switch (expired_timer) {
     950             :         case IEEE80211_MIRA_PROBE_TO_UP:
     951             :                 /* Do time-based upwards probing on next frame. */
     952             :                 DPRINTFN(2, ("probe timer expired: probe upwards\n"));
     953           0 :                 mn->probing = IEEE80211_MIRA_PROBING_UP;
     954           0 :                 mcs = ieee80211_mira_next_intra_rate(mn, ni);
     955           0 :                 mn->candidate_rates = (1 << mcs);
     956             :                 ret = 1;
     957           0 :                 break;
     958             :         case IEEE80211_MIRA_PROBE_TO_DOWN:
     959             :                 /* Do time-based downwards probing on next frame. */
     960             :                 DPRINTFN(2, ("probe timer expired: probe downwards\n"));
     961           0 :                 mn->probing = IEEE80211_MIRA_PROBING_DOWN;
     962           0 :                 mcs = ieee80211_mira_next_lower_intra_rate(mn, ni);
     963           0 :                 mn->candidate_rates = (1 << mcs);
     964             :                 ret = 1;
     965           0 :                 break;
     966             :         case IEEE80211_MIRA_PROBE_TO_INVALID:
     967             :         default:
     968             :                 ret = 0;
     969           0 :                 break;
     970             :         }
     971             : 
     972           0 :         return ret;
     973             : }
     974             : 
     975             : void
     976           0 : ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *mn,
     977             :     struct ieee80211_node *ni)
     978             : {
     979             :         struct ieee80211_mira_goodput_stats *gprev, *g;
     980             :         int prev_mcs;
     981             : 
     982           0 :         prev_mcs = ieee80211_mira_prev_mcs(mn, ni);
     983           0 :         gprev = &mn->g[prev_mcs];
     984           0 :         g = &mn->g[ni->ni_txmcs];
     985             :         /* If the previous rate was worse, increase its probing interval. */
     986           0 :         if (prev_mcs != ni->ni_txmcs &&
     987           0 :             gprev->measured + IEEE80211_MIRA_RATE_THRESHOLD < g->measured)
     988           0 :                 ieee80211_mira_update_probe_interval(mn, gprev);
     989             : 
     990             :         /* Select the next rate to probe. */
     991           0 :         mn->probed_rates |= (1 << ni->ni_txmcs);
     992           0 :         ni->ni_txmcs = ieee80211_mira_next_mcs(mn, ni);
     993           0 : }
     994             : 
     995             : int
     996           0 : ieee80211_mira_valid_tx_mcs(struct ieee80211com *ic, int mcs)
     997             : {
     998             :         uint32_t ntxstreams = 1;
     999             :         static const int max_mcs[] = { 7, 15, 23, 31 };
    1000             : 
    1001           0 :         if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0)
    1002           0 :                 return isset(ic->ic_sup_mcs, mcs);
    1003             : 
    1004           0 :         ntxstreams += ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2);
    1005           0 :         if (ntxstreams < 1 || ntxstreams > 4)
    1006           0 :                 panic("invalid number of Tx streams: %u", ntxstreams);
    1007           0 :         return (mcs <= max_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs));
    1008           0 : }
    1009             : 
    1010             : uint32_t
    1011           0 : ieee80211_mira_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni)
    1012             : {
    1013             :         uint32_t valid_mcs = 0;
    1014             :         int i;
    1015             : 
    1016           0 :         for (i = 0;
    1017           0 :             i < MIN(IEEE80211_MIRA_NUM_MCS, IEEE80211_HT_NUM_MCS); i++) {
    1018           0 :                 if (!isset(ni->ni_rxmcs, i))
    1019             :                         continue;
    1020           0 :                 if (!ieee80211_mira_valid_tx_mcs(ic, i))
    1021             :                         continue;
    1022           0 :                 valid_mcs |= (1 << i);
    1023           0 :         }
    1024             : 
    1025           0 :         return valid_mcs;
    1026             : }
    1027             : 
    1028             : uint32_t
    1029           0 : ieee80211_mira_mcs_below(struct ieee80211_mira_node *mn, int mcs)
    1030             : {
    1031             :         const struct ieee80211_mira_rateset *rs;
    1032             :         uint32_t mcs_mask;
    1033             :         int i;
    1034             : 
    1035           0 :         rs = ieee80211_mira_get_rateset(mcs);
    1036           0 :         mcs_mask = (1 << rs->min_mcs);
    1037           0 :         for (i = rs->min_mcs + 1; i < mcs; i++) {
    1038           0 :                 if ((mn->valid_rates & (1 << i)) == 0)
    1039             :                         continue;
    1040           0 :                 mcs_mask |= (1 << i);
    1041           0 :         }
    1042             : 
    1043           0 :         return mcs_mask;
    1044             : }
    1045             : 
    1046             : void
    1047           0 : ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com *ic,
    1048             :     struct ieee80211_node *ni)
    1049             : {
    1050           0 :         struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
    1051             :         int s;
    1052             : 
    1053           0 :         s = splnet();
    1054             : 
    1055           0 :         if (mn->valid_rates == 0)
    1056           0 :                 mn->valid_rates = ieee80211_mira_valid_rates(ic, ni);
    1057             : 
    1058             : #ifdef MIRA_DEBUG
    1059             :         if (mira_debug >= 5)
    1060             :                 mira_print_driver_stats(mn, ni);
    1061             : #endif
    1062           0 :         ieee80211_mira_update_stats(mn, ic, ni);
    1063             : 
    1064           0 :         if (mn->probing) {
    1065             :                 /* Probe another rate or settle at the best rate. */
    1066           0 :                 if (!ieee80211_mira_intra_mode_ra_finished(mn, ni)) {
    1067           0 :                         if (ieee80211_mira_probe_valid(mn, ni)) {
    1068           0 :                                 ieee80211_mira_probe_next_rate(mn, ni);
    1069           0 :                                 ieee80211_mira_reset_driver_stats(mn);
    1070           0 :                         }
    1071             :                         DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs));
    1072           0 :                 } else if (ieee80211_mira_inter_mode_ra_finished(mn, ni)) {
    1073           0 :                         int best = ieee80211_mira_best_rate(mn, ni);
    1074           0 :                         if (mn->best_mcs != best) {
    1075           0 :                                 mn->best_mcs = best;
    1076           0 :                                 ni->ni_txmcs = best;
    1077             :                                 /* Reset probe interval for new best rate. */
    1078           0 :                                 mn->g[best].probe_interval =
    1079             :                                     IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
    1080           0 :                                 mn->g[best].nprobes = 0;
    1081           0 :                                 mn->g[best].nprobe_bytes = 0;
    1082           0 :                         } else
    1083           0 :                                 ni->ni_txmcs = mn->best_mcs;
    1084           0 :                         ieee80211_mira_probe_done(mn);
    1085           0 :                 }
    1086             : 
    1087           0 :                 splx(s);
    1088           0 :                 return;
    1089             :         } else {
    1090           0 :                 ieee80211_mira_reset_driver_stats(mn);
    1091           0 :                 ieee80211_mira_schedule_probe_timers(mn, ni);
    1092             :         }
    1093             : 
    1094           0 :         if (ieee80211_mira_check_probe_timers(mn, ni)) {
    1095             :                 /* Time-based probing has triggered. */
    1096           0 :                 splx(s);
    1097           0 :                 return;
    1098             :         }
    1099             : 
    1100             :         /* Check if event-based probing should be triggered. */
    1101           0 :         if (g->measured <= g->average - 2 * g->stddeviation) {
    1102             :                 /* Channel becomes bad. Probe downwards. */
    1103             :                 DPRINTFN(2, ("channel becomes bad; probe downwards\n"));
    1104             :                 DPRINTFN(3, ("measured: %s Mbit/s\n",
    1105             :                     mira_fp_sprintf(g->measured)));
    1106             :                 DPRINTFN(3, ("average: %s Mbit/s\n",
    1107             :                     mira_fp_sprintf(g->average)));
    1108             :                 DPRINTFN(3, ("stddeviation: %s\n",
    1109             :                     mira_fp_sprintf(g->stddeviation)));
    1110           0 :                 mn->probing = IEEE80211_MIRA_PROBING_DOWN;
    1111           0 :                 mn->probed_rates = 0;
    1112             : #ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
    1113             :                 /* Allow for probing all the way down within this rateset. */
    1114           0 :                 mn->candidate_rates = ieee80211_mira_mcs_below(mn,
    1115           0 :                     ni->ni_txmcs);
    1116             : #else
    1117             :                 /* Probe the lower candidate rate to see if it's any better. */
    1118             :                 mn->candidate_rates =
    1119             :                     (1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
    1120             : #endif
    1121           0 :         } else if (g->measured >= g->average + 2 * g->stddeviation) {
    1122             :                 /* Channel becomes good. */
    1123             :                 DPRINTFN(2, ("channel becomes good; probe upwards\n"));
    1124             :                 DPRINTFN(3, ("measured: %s Mbit/s\n",
    1125             :                     mira_fp_sprintf(g->measured)));
    1126             :                 DPRINTFN(3, ("average: %s Mbit/s\n",
    1127             :                     mira_fp_sprintf(g->average)));
    1128             :                 DPRINTFN(3, ("stddeviation: %s\n",
    1129             :                     mira_fp_sprintf(g->stddeviation)));
    1130           0 :                 mn->probing = IEEE80211_MIRA_PROBING_UP;
    1131           0 :                 mn->probed_rates = 0;
    1132             :                 /* Probe the upper candidate rate to see if it's any better. */
    1133           0 :                 mn->candidate_rates =
    1134           0 :                     (1 << ieee80211_mira_next_intra_rate(mn, ni));
    1135           0 :         } else {
    1136             :                 /* Remain at current rate. */
    1137           0 :                 mn->probing = IEEE80211_MIRA_NOT_PROBING;
    1138           0 :                 mn->probed_rates = 0;
    1139           0 :                 mn->candidate_rates = 0;
    1140             :         }
    1141             : 
    1142           0 :         splx(s);
    1143           0 : }
    1144             : 
    1145             : void
    1146           0 : ieee80211_mira_node_init(struct ieee80211_mira_node *mn)
    1147             : {
    1148           0 :         memset(mn, 0, sizeof(*mn));
    1149           0 :         mn->agglen = 1;
    1150           0 :         ieee80211_mira_reset_goodput_stats(mn);
    1151             : 
    1152           0 :         timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP],
    1153             :             ieee80211_mira_probe_timeout_up, mn);
    1154           0 :         timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN],
    1155             :             ieee80211_mira_probe_timeout_down, mn);
    1156           0 : }
    1157             : 
    1158             : void
    1159           0 : ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *mn)
    1160             : {
    1161             :         int t;
    1162             : 
    1163           0 :         for (t = 0; t < nitems(mn->probe_to); t++)
    1164           0 :                 timeout_del(&mn->probe_to[t]);
    1165           0 : }

Generated by: LCOV version 1.13