1*04171cfcSAugustin Cavalier /* $OpenBSD: ieee80211_ra.c,v 1.5 2022/03/19 10:28:44 stsp Exp $ */ 2*04171cfcSAugustin Cavalier 3*04171cfcSAugustin Cavalier /* 4*04171cfcSAugustin Cavalier * Copyright (c) 2021 Christian Ehrhardt <ehrhardt@genua.de> 5*04171cfcSAugustin Cavalier * Copyright (c) 2016, 2021 Stefan Sperling <stsp@openbsd.org> 6*04171cfcSAugustin Cavalier * Copyright (c) 2016 Theo Buehler <tb@openbsd.org> 7*04171cfcSAugustin Cavalier * 8*04171cfcSAugustin Cavalier * Permission to use, copy, modify, and distribute this software for any 9*04171cfcSAugustin Cavalier * purpose with or without fee is hereby granted, provided that the above 10*04171cfcSAugustin Cavalier * copyright notice and this permission notice appear in all copies. 11*04171cfcSAugustin Cavalier * 12*04171cfcSAugustin Cavalier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13*04171cfcSAugustin Cavalier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14*04171cfcSAugustin Cavalier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15*04171cfcSAugustin Cavalier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16*04171cfcSAugustin Cavalier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17*04171cfcSAugustin Cavalier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18*04171cfcSAugustin Cavalier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19*04171cfcSAugustin Cavalier */ 20*04171cfcSAugustin Cavalier 21*04171cfcSAugustin Cavalier #include <sys/param.h> 22*04171cfcSAugustin Cavalier #include <sys/systm.h> 23*04171cfcSAugustin Cavalier #include <sys/socket.h> 24*04171cfcSAugustin Cavalier 25*04171cfcSAugustin Cavalier #include <net/if.h> 26*04171cfcSAugustin Cavalier #include <net/if_media.h> 27*04171cfcSAugustin Cavalier 28*04171cfcSAugustin Cavalier #include <netinet/in.h> 29*04171cfcSAugustin Cavalier #include <netinet/if_ether.h> 30*04171cfcSAugustin Cavalier 31*04171cfcSAugustin Cavalier #include <net80211/ieee80211_var.h> 32*04171cfcSAugustin Cavalier #include <net80211/ieee80211_ra.h> 33*04171cfcSAugustin Cavalier 34*04171cfcSAugustin Cavalier int ieee80211_ra_next_intra_rate(struct ieee80211_ra_node *, 35*04171cfcSAugustin Cavalier struct ieee80211_node *); 36*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset * ieee80211_ra_next_rateset( 37*04171cfcSAugustin Cavalier struct ieee80211_ra_node *, struct ieee80211_node *); 38*04171cfcSAugustin Cavalier int ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node *, 39*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *); 40*04171cfcSAugustin Cavalier void ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node *, 41*04171cfcSAugustin Cavalier struct ieee80211_node *, const struct ieee80211_ht_rateset *); 42*04171cfcSAugustin Cavalier int ieee80211_ra_next_mcs(struct ieee80211_ra_node *, 43*04171cfcSAugustin Cavalier struct ieee80211_node *); 44*04171cfcSAugustin Cavalier void ieee80211_ra_probe_done(struct ieee80211_ra_node *); 45*04171cfcSAugustin Cavalier int ieee80211_ra_intra_mode_ra_finished( 46*04171cfcSAugustin Cavalier struct ieee80211_ra_node *, struct ieee80211_node *); 47*04171cfcSAugustin Cavalier void ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node *, 48*04171cfcSAugustin Cavalier struct ieee80211_node *); 49*04171cfcSAugustin Cavalier int ieee80211_ra_inter_mode_ra_finished( 50*04171cfcSAugustin Cavalier struct ieee80211_ra_node *, struct ieee80211_node *); 51*04171cfcSAugustin Cavalier int ieee80211_ra_best_rate(struct ieee80211_ra_node *, 52*04171cfcSAugustin Cavalier struct ieee80211_node *); 53*04171cfcSAugustin Cavalier void ieee80211_ra_probe_next_rate(struct ieee80211_ra_node *, 54*04171cfcSAugustin Cavalier struct ieee80211_node *); 55*04171cfcSAugustin Cavalier int ieee80211_ra_valid_tx_mcs(struct ieee80211com *, int); 56*04171cfcSAugustin Cavalier uint32_t ieee80211_ra_valid_rates(struct ieee80211com *, 57*04171cfcSAugustin Cavalier struct ieee80211_node *); 58*04171cfcSAugustin Cavalier int ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats *); 59*04171cfcSAugustin Cavalier 60*04171cfcSAugustin Cavalier /* We use fixed point arithmetic with 64 bit integers. */ 61*04171cfcSAugustin Cavalier #define RA_FP_SHIFT 21 62*04171cfcSAugustin Cavalier #define RA_FP_INT(x) (x ## ULL << RA_FP_SHIFT) /* the integer x */ 63*04171cfcSAugustin Cavalier #define RA_FP_1 RA_FP_INT(1) 64*04171cfcSAugustin Cavalier 65*04171cfcSAugustin Cavalier /* Multiply two fixed point numbers. */ 66*04171cfcSAugustin Cavalier #define RA_FP_MUL(a, b) \ 67*04171cfcSAugustin Cavalier (((a) * (b)) >> RA_FP_SHIFT) 68*04171cfcSAugustin Cavalier 69*04171cfcSAugustin Cavalier /* Divide two fixed point numbers. */ 70*04171cfcSAugustin Cavalier #define RA_FP_DIV(a, b) \ 71*04171cfcSAugustin Cavalier (b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT) / (b))) 72*04171cfcSAugustin Cavalier 73*04171cfcSAugustin Cavalier #ifdef RA_DEBUG 74*04171cfcSAugustin Cavalier #define DPRINTF(x) do { if (ra_debug > 0) printf x; } while (0) 75*04171cfcSAugustin Cavalier #define DPRINTFN(n, x) do { if (ra_debug >= (n)) printf x; } while (0) 76*04171cfcSAugustin Cavalier int ra_debug = 0; 77*04171cfcSAugustin Cavalier #else 78*04171cfcSAugustin Cavalier #define DPRINTF(x) do { ; } while (0) 79*04171cfcSAugustin Cavalier #define DPRINTFN(n, x) do { ; } while (0) 80*04171cfcSAugustin Cavalier #endif 81*04171cfcSAugustin Cavalier 82*04171cfcSAugustin Cavalier #ifdef RA_DEBUG 83*04171cfcSAugustin Cavalier void 84*04171cfcSAugustin Cavalier ra_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp) 85*04171cfcSAugustin Cavalier { 86*04171cfcSAugustin Cavalier uint64_t tmp; 87*04171cfcSAugustin Cavalier 88*04171cfcSAugustin Cavalier /* integer part */ 89*04171cfcSAugustin Cavalier *i = (fp >> RA_FP_SHIFT); 90*04171cfcSAugustin Cavalier 91*04171cfcSAugustin Cavalier /* fractional part */ 92*04171cfcSAugustin Cavalier tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT))); 93*04171cfcSAugustin Cavalier tmp *= 100; 94*04171cfcSAugustin Cavalier *f = (uint32_t)(tmp >> RA_FP_SHIFT); 95*04171cfcSAugustin Cavalier } 96*04171cfcSAugustin Cavalier 97*04171cfcSAugustin Cavalier char * 98*04171cfcSAugustin Cavalier ra_fp_sprintf(uint64_t fp) 99*04171cfcSAugustin Cavalier { 100*04171cfcSAugustin Cavalier uint32_t i, f; 101*04171cfcSAugustin Cavalier static char buf[64]; 102*04171cfcSAugustin Cavalier int ret; 103*04171cfcSAugustin Cavalier 104*04171cfcSAugustin Cavalier ra_fixedp_split(&i, &f, fp); 105*04171cfcSAugustin Cavalier ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f); 106*04171cfcSAugustin Cavalier if (ret == -1 || ret >= sizeof(buf)) 107*04171cfcSAugustin Cavalier return "ERR"; 108*04171cfcSAugustin Cavalier 109*04171cfcSAugustin Cavalier return buf; 110*04171cfcSAugustin Cavalier } 111*04171cfcSAugustin Cavalier #endif /* RA_DEBUG */ 112*04171cfcSAugustin Cavalier 113*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset * 114*04171cfcSAugustin Cavalier ieee80211_ra_get_ht_rateset(int mcs, int chan40, int sgi) 115*04171cfcSAugustin Cavalier { 116*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs; 117*04171cfcSAugustin Cavalier int i; 118*04171cfcSAugustin Cavalier 119*04171cfcSAugustin Cavalier for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) { 120*04171cfcSAugustin Cavalier rs = &ieee80211_std_ratesets_11n[i]; 121*04171cfcSAugustin Cavalier if (chan40 == rs->chan40 && sgi == rs->sgi && 122*04171cfcSAugustin Cavalier mcs >= rs->min_mcs && mcs <= rs->max_mcs) 123*04171cfcSAugustin Cavalier return rs; 124*04171cfcSAugustin Cavalier } 125*04171cfcSAugustin Cavalier 126*04171cfcSAugustin Cavalier panic("MCS %d is not part of any rateset", mcs); 127*04171cfcSAugustin Cavalier } 128*04171cfcSAugustin Cavalier 129*04171cfcSAugustin Cavalier int 130*04171cfcSAugustin Cavalier ieee80211_ra_use_ht_sgi(struct ieee80211_node *ni) 131*04171cfcSAugustin Cavalier { 132*04171cfcSAugustin Cavalier if ((ni->ni_chan->ic_flags & IEEE80211_CHAN_40MHZ) && 133*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni)) { 134*04171cfcSAugustin Cavalier if (ni->ni_flags & IEEE80211_NODE_HT_SGI40) 135*04171cfcSAugustin Cavalier return 1; 136*04171cfcSAugustin Cavalier } else if (ni->ni_flags & IEEE80211_NODE_HT_SGI20) 137*04171cfcSAugustin Cavalier return 1; 138*04171cfcSAugustin Cavalier 139*04171cfcSAugustin Cavalier return 0; 140*04171cfcSAugustin Cavalier } 141*04171cfcSAugustin Cavalier 142*04171cfcSAugustin Cavalier /* 143*04171cfcSAugustin Cavalier * Update goodput statistics. 144*04171cfcSAugustin Cavalier */ 145*04171cfcSAugustin Cavalier 146*04171cfcSAugustin Cavalier uint64_t 147*04171cfcSAugustin Cavalier ieee80211_ra_get_txrate(int mcs, int chan40, int sgi) 148*04171cfcSAugustin Cavalier { 149*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs; 150*04171cfcSAugustin Cavalier uint64_t txrate; 151*04171cfcSAugustin Cavalier 152*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(mcs, chan40, sgi); 153*04171cfcSAugustin Cavalier txrate = rs->rates[mcs - rs->min_mcs]; 154*04171cfcSAugustin Cavalier txrate <<= RA_FP_SHIFT; /* convert to fixed-point */ 155*04171cfcSAugustin Cavalier txrate *= 500; /* convert to kbit/s */ 156*04171cfcSAugustin Cavalier txrate /= 1000; /* convert to mbit/s */ 157*04171cfcSAugustin Cavalier 158*04171cfcSAugustin Cavalier return txrate; 159*04171cfcSAugustin Cavalier } 160*04171cfcSAugustin Cavalier 161*04171cfcSAugustin Cavalier /* 162*04171cfcSAugustin Cavalier * Rate selection. 163*04171cfcSAugustin Cavalier */ 164*04171cfcSAugustin Cavalier 165*04171cfcSAugustin Cavalier /* A rate's goodput has to be at least this much larger to be "better". */ 166*04171cfcSAugustin Cavalier #define IEEE80211_RA_RATE_THRESHOLD (RA_FP_1 / 64) /* ~ 0.015 */ 167*04171cfcSAugustin Cavalier 168*04171cfcSAugustin Cavalier int 169*04171cfcSAugustin Cavalier ieee80211_ra_next_lower_intra_rate(struct ieee80211_ra_node *rn, 170*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 171*04171cfcSAugustin Cavalier { 172*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs; 173*04171cfcSAugustin Cavalier int i, next; 174*04171cfcSAugustin Cavalier 175*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, 176*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni)); 177*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->min_mcs) 178*04171cfcSAugustin Cavalier return rs->min_mcs; 179*04171cfcSAugustin Cavalier 180*04171cfcSAugustin Cavalier next = ni->ni_txmcs; 181*04171cfcSAugustin Cavalier for (i = rs->nrates - 1; i >= 0; i--) { 182*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << (i + rs->min_mcs))) == 0) 183*04171cfcSAugustin Cavalier continue; 184*04171cfcSAugustin Cavalier if (i + rs->min_mcs < ni->ni_txmcs) { 185*04171cfcSAugustin Cavalier next = i + rs->min_mcs; 186*04171cfcSAugustin Cavalier break; 187*04171cfcSAugustin Cavalier } 188*04171cfcSAugustin Cavalier } 189*04171cfcSAugustin Cavalier 190*04171cfcSAugustin Cavalier return next; 191*04171cfcSAugustin Cavalier } 192*04171cfcSAugustin Cavalier 193*04171cfcSAugustin Cavalier int 194*04171cfcSAugustin Cavalier ieee80211_ra_next_intra_rate(struct ieee80211_ra_node *rn, 195*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 196*04171cfcSAugustin Cavalier { 197*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs; 198*04171cfcSAugustin Cavalier int i, next; 199*04171cfcSAugustin Cavalier 200*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, 201*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni)); 202*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->max_mcs) 203*04171cfcSAugustin Cavalier return rs->max_mcs; 204*04171cfcSAugustin Cavalier 205*04171cfcSAugustin Cavalier next = ni->ni_txmcs; 206*04171cfcSAugustin Cavalier for (i = 0; i < rs->nrates; i++) { 207*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << (i + rs->min_mcs))) == 0) 208*04171cfcSAugustin Cavalier continue; 209*04171cfcSAugustin Cavalier if (i + rs->min_mcs > ni->ni_txmcs) { 210*04171cfcSAugustin Cavalier next = i + rs->min_mcs; 211*04171cfcSAugustin Cavalier break; 212*04171cfcSAugustin Cavalier } 213*04171cfcSAugustin Cavalier } 214*04171cfcSAugustin Cavalier 215*04171cfcSAugustin Cavalier return next; 216*04171cfcSAugustin Cavalier } 217*04171cfcSAugustin Cavalier 218*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset * 219*04171cfcSAugustin Cavalier ieee80211_ra_next_rateset(struct ieee80211_ra_node *rn, 220*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 221*04171cfcSAugustin Cavalier { 222*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs, *rsnext; 223*04171cfcSAugustin Cavalier int next; 224*04171cfcSAugustin Cavalier int chan40 = ieee80211_node_supports_ht_chan40(ni); 225*04171cfcSAugustin Cavalier int sgi = ieee80211_ra_use_ht_sgi(ni); 226*04171cfcSAugustin Cavalier int mcs = ni->ni_txmcs; 227*04171cfcSAugustin Cavalier 228*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(mcs, chan40, sgi); 229*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_UP) { 230*04171cfcSAugustin Cavalier if (rs->max_mcs == 7) { /* MCS 0-7 */ 231*04171cfcSAugustin Cavalier if (chan40) 232*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI40 : 233*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2_40; 234*04171cfcSAugustin Cavalier else 235*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI : 236*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2; 237*04171cfcSAugustin Cavalier } else if (rs->max_mcs == 15) { /* MCS 8-15 */ 238*04171cfcSAugustin Cavalier if (chan40) 239*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI40 : 240*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3_40; 241*04171cfcSAugustin Cavalier else 242*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI : 243*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3; 244*04171cfcSAugustin Cavalier } else if (rs->max_mcs == 23) { /* MCS 16-23 */ 245*04171cfcSAugustin Cavalier if (chan40) 246*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI40 : 247*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO4_40; 248*04171cfcSAugustin Cavalier else 249*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI : 250*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO4; 251*04171cfcSAugustin Cavalier } else /* MCS 24-31 */ 252*04171cfcSAugustin Cavalier return NULL; 253*04171cfcSAugustin Cavalier } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) { 254*04171cfcSAugustin Cavalier if (rs->min_mcs == 24) { /* MCS 24-31 */ 255*04171cfcSAugustin Cavalier if (chan40) 256*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI40 : 257*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3_40; 258*04171cfcSAugustin Cavalier else 259*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI : 260*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3; 261*04171cfcSAugustin Cavalier } else if (rs->min_mcs == 16) { /* MCS 16-23 */ 262*04171cfcSAugustin Cavalier if (chan40) 263*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI40 : 264*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2_40; 265*04171cfcSAugustin Cavalier else 266*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI : 267*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2; 268*04171cfcSAugustin Cavalier } else if (rs->min_mcs == 8) { /* MCS 8-15 */ 269*04171cfcSAugustin Cavalier if (chan40) 270*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_SISO_SGI40 : 271*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_SISO_40; 272*04171cfcSAugustin Cavalier else 273*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_SISO_SGI : 274*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_SISO; 275*04171cfcSAugustin Cavalier } else /* MCS 0-7 */ 276*04171cfcSAugustin Cavalier return NULL; 277*04171cfcSAugustin Cavalier } else 278*04171cfcSAugustin Cavalier panic("%s: invalid probing mode %d", __func__, rn->probing); 279*04171cfcSAugustin Cavalier 280*04171cfcSAugustin Cavalier rsnext = &ieee80211_std_ratesets_11n[next]; 281*04171cfcSAugustin Cavalier if ((rsnext->mcs_mask & rn->valid_rates) == 0) 282*04171cfcSAugustin Cavalier return NULL; 283*04171cfcSAugustin Cavalier 284*04171cfcSAugustin Cavalier return rsnext; 285*04171cfcSAugustin Cavalier } 286*04171cfcSAugustin Cavalier 287*04171cfcSAugustin Cavalier int 288*04171cfcSAugustin Cavalier ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node *rn, 289*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs) 290*04171cfcSAugustin Cavalier { 291*04171cfcSAugustin Cavalier uint64_t gmax = 0; 292*04171cfcSAugustin Cavalier int i, best_mcs = rs->min_mcs; 293*04171cfcSAugustin Cavalier 294*04171cfcSAugustin Cavalier for (i = 0; i < rs->nrates; i++) { 295*04171cfcSAugustin Cavalier int mcs = rs->min_mcs + i; 296*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[mcs]; 297*04171cfcSAugustin Cavalier if (((1 << mcs) & rn->valid_rates) == 0) 298*04171cfcSAugustin Cavalier continue; 299*04171cfcSAugustin Cavalier if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) { 300*04171cfcSAugustin Cavalier gmax = g->measured; 301*04171cfcSAugustin Cavalier best_mcs = mcs; 302*04171cfcSAugustin Cavalier } 303*04171cfcSAugustin Cavalier } 304*04171cfcSAugustin Cavalier 305*04171cfcSAugustin Cavalier return best_mcs; 306*04171cfcSAugustin Cavalier } 307*04171cfcSAugustin Cavalier 308*04171cfcSAugustin Cavalier void 309*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node *rn, 310*04171cfcSAugustin Cavalier struct ieee80211_node *ni, const struct ieee80211_ht_rateset *rsnext) 311*04171cfcSAugustin Cavalier { 312*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs; 313*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g; 314*04171cfcSAugustin Cavalier int best_mcs, i; 315*04171cfcSAugustin Cavalier 316*04171cfcSAugustin Cavalier /* Find most recently measured best MCS from the current rateset. */ 317*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, 318*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni)); 319*04171cfcSAugustin Cavalier best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs); 320*04171cfcSAugustin Cavalier 321*04171cfcSAugustin Cavalier /* Switch to the next rateset. */ 322*04171cfcSAugustin Cavalier ni->ni_txmcs = rsnext->min_mcs; 323*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << rsnext->min_mcs)) == 0) 324*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_intra_rate(rn, ni); 325*04171cfcSAugustin Cavalier 326*04171cfcSAugustin Cavalier /* Select the lowest rate from the next rateset with loss-free 327*04171cfcSAugustin Cavalier * goodput close to the current best measurement. */ 328*04171cfcSAugustin Cavalier g = &rn->g[best_mcs]; 329*04171cfcSAugustin Cavalier for (i = 0; i < rsnext->nrates; i++) { 330*04171cfcSAugustin Cavalier int mcs = rsnext->min_mcs + i; 331*04171cfcSAugustin Cavalier uint64_t txrate = rsnext->rates[i]; 332*04171cfcSAugustin Cavalier 333*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << mcs)) == 0) 334*04171cfcSAugustin Cavalier continue; 335*04171cfcSAugustin Cavalier 336*04171cfcSAugustin Cavalier txrate = txrate * 500; /* convert to kbit/s */ 337*04171cfcSAugustin Cavalier txrate <<= RA_FP_SHIFT; /* convert to fixed-point */ 338*04171cfcSAugustin Cavalier txrate /= 1000; /* convert to mbit/s */ 339*04171cfcSAugustin Cavalier 340*04171cfcSAugustin Cavalier if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD) { 341*04171cfcSAugustin Cavalier ni->ni_txmcs = mcs; 342*04171cfcSAugustin Cavalier break; 343*04171cfcSAugustin Cavalier } 344*04171cfcSAugustin Cavalier } 345*04171cfcSAugustin Cavalier /* If all rates are lower the maximum rate is the closest match. */ 346*04171cfcSAugustin Cavalier if (i == rsnext->nrates) 347*04171cfcSAugustin Cavalier ni->ni_txmcs = rsnext->max_mcs; 348*04171cfcSAugustin Cavalier 349*04171cfcSAugustin Cavalier /* Add rates from the next rateset as candidates. */ 350*04171cfcSAugustin Cavalier rn->candidate_rates |= (1 << ni->ni_txmcs); 351*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_UP) { 352*04171cfcSAugustin Cavalier rn->candidate_rates |= 353*04171cfcSAugustin Cavalier (1 << ieee80211_ra_next_intra_rate(rn, ni)); 354*04171cfcSAugustin Cavalier } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) { 355*04171cfcSAugustin Cavalier rn->candidate_rates |= 356*04171cfcSAugustin Cavalier (1 << ieee80211_ra_next_lower_intra_rate(rn, ni)); 357*04171cfcSAugustin Cavalier } else 358*04171cfcSAugustin Cavalier panic("%s: invalid probing mode %d", __func__, rn->probing); 359*04171cfcSAugustin Cavalier } 360*04171cfcSAugustin Cavalier 361*04171cfcSAugustin Cavalier int 362*04171cfcSAugustin Cavalier ieee80211_ra_next_mcs(struct ieee80211_ra_node *rn, 363*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 364*04171cfcSAugustin Cavalier { 365*04171cfcSAugustin Cavalier int next; 366*04171cfcSAugustin Cavalier 367*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_DOWN) 368*04171cfcSAugustin Cavalier next = ieee80211_ra_next_lower_intra_rate(rn, ni); 369*04171cfcSAugustin Cavalier else if (rn->probing & IEEE80211_RA_PROBING_UP) 370*04171cfcSAugustin Cavalier next = ieee80211_ra_next_intra_rate(rn, ni); 371*04171cfcSAugustin Cavalier else 372*04171cfcSAugustin Cavalier panic("%s: invalid probing mode %d", __func__, rn->probing); 373*04171cfcSAugustin Cavalier 374*04171cfcSAugustin Cavalier return next; 375*04171cfcSAugustin Cavalier } 376*04171cfcSAugustin Cavalier 377*04171cfcSAugustin Cavalier void 378*04171cfcSAugustin Cavalier ieee80211_ra_probe_clear(struct ieee80211_ra_node *rn, 379*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 380*04171cfcSAugustin Cavalier { 381*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs]; 382*04171cfcSAugustin Cavalier 383*04171cfcSAugustin Cavalier g->nprobe_pkts = 0; 384*04171cfcSAugustin Cavalier g->nprobe_fail = 0; 385*04171cfcSAugustin Cavalier } 386*04171cfcSAugustin Cavalier 387*04171cfcSAugustin Cavalier void 388*04171cfcSAugustin Cavalier ieee80211_ra_probe_done(struct ieee80211_ra_node *rn) 389*04171cfcSAugustin Cavalier { 390*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING; 391*04171cfcSAugustin Cavalier rn->probed_rates = 0; 392*04171cfcSAugustin Cavalier rn->valid_probes = 0; 393*04171cfcSAugustin Cavalier rn->candidate_rates = 0; 394*04171cfcSAugustin Cavalier } 395*04171cfcSAugustin Cavalier 396*04171cfcSAugustin Cavalier int 397*04171cfcSAugustin Cavalier ieee80211_ra_intra_mode_ra_finished(struct ieee80211_ra_node *rn, 398*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 399*04171cfcSAugustin Cavalier { 400*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs; 401*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs]; 402*04171cfcSAugustin Cavalier int next_mcs, best_mcs; 403*04171cfcSAugustin Cavalier uint64_t next_rate; 404*04171cfcSAugustin Cavalier int chan40 = ieee80211_node_supports_ht_chan40(ni); 405*04171cfcSAugustin Cavalier int sgi = ieee80211_ra_use_ht_sgi(ni); 406*04171cfcSAugustin Cavalier 407*04171cfcSAugustin Cavalier rn->probed_rates = (rn->probed_rates | (1 << ni->ni_txmcs)); 408*04171cfcSAugustin Cavalier 409*04171cfcSAugustin Cavalier /* Check if the min/max MCS in this rateset has been probed. */ 410*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, chan40, sgi); 411*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_DOWN) { 412*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->min_mcs || 413*04171cfcSAugustin Cavalier rn->probed_rates & (1 << rs->min_mcs)) { 414*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni); 415*04171cfcSAugustin Cavalier return 1; 416*04171cfcSAugustin Cavalier } 417*04171cfcSAugustin Cavalier } else if (rn->probing & IEEE80211_RA_PROBING_UP) { 418*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->max_mcs || 419*04171cfcSAugustin Cavalier rn->probed_rates & (1 << rs->max_mcs)) { 420*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni); 421*04171cfcSAugustin Cavalier return 1; 422*04171cfcSAugustin Cavalier } 423*04171cfcSAugustin Cavalier } 424*04171cfcSAugustin Cavalier 425*04171cfcSAugustin Cavalier /* 426*04171cfcSAugustin Cavalier * Check if the measured goodput is loss-free and better than the 427*04171cfcSAugustin Cavalier * loss-free goodput of the candidate rate. 428*04171cfcSAugustin Cavalier */ 429*04171cfcSAugustin Cavalier next_mcs = ieee80211_ra_next_mcs(rn, ni); 430*04171cfcSAugustin Cavalier if (next_mcs == ni->ni_txmcs) { 431*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni); 432*04171cfcSAugustin Cavalier return 1; 433*04171cfcSAugustin Cavalier } 434*04171cfcSAugustin Cavalier next_rate = ieee80211_ra_get_txrate(next_mcs, chan40, sgi); 435*04171cfcSAugustin Cavalier if (g->loss == 0 && 436*04171cfcSAugustin Cavalier g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) { 437*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni); 438*04171cfcSAugustin Cavalier return 1; 439*04171cfcSAugustin Cavalier } 440*04171cfcSAugustin Cavalier 441*04171cfcSAugustin Cavalier /* Check if we had a better measurement at a previously probed MCS. */ 442*04171cfcSAugustin Cavalier best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs); 443*04171cfcSAugustin Cavalier if (best_mcs != ni->ni_txmcs && (rn->probed_rates & (1 << best_mcs))) { 444*04171cfcSAugustin Cavalier if ((rn->probing & IEEE80211_RA_PROBING_UP) && 445*04171cfcSAugustin Cavalier best_mcs < ni->ni_txmcs) { 446*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni); 447*04171cfcSAugustin Cavalier return 1; 448*04171cfcSAugustin Cavalier } 449*04171cfcSAugustin Cavalier if ((rn->probing & IEEE80211_RA_PROBING_DOWN) && 450*04171cfcSAugustin Cavalier best_mcs > ni->ni_txmcs) { 451*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni); 452*04171cfcSAugustin Cavalier return 1; 453*04171cfcSAugustin Cavalier } 454*04171cfcSAugustin Cavalier } 455*04171cfcSAugustin Cavalier 456*04171cfcSAugustin Cavalier /* Check if all rates in the set of candidate rates have been probed. */ 457*04171cfcSAugustin Cavalier if ((rn->candidate_rates & rn->probed_rates) == rn->candidate_rates) { 458*04171cfcSAugustin Cavalier /* Remain in the current rateset until above checks trigger. */ 459*04171cfcSAugustin Cavalier rn->probing &= ~IEEE80211_RA_PROBING_INTER; 460*04171cfcSAugustin Cavalier return 1; 461*04171cfcSAugustin Cavalier } 462*04171cfcSAugustin Cavalier 463*04171cfcSAugustin Cavalier return 0; 464*04171cfcSAugustin Cavalier } 465*04171cfcSAugustin Cavalier 466*04171cfcSAugustin Cavalier void 467*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node *rn, 468*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 469*04171cfcSAugustin Cavalier { 470*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rsnext; 471*04171cfcSAugustin Cavalier 472*04171cfcSAugustin Cavalier rsnext = ieee80211_ra_next_rateset(rn, ni); 473*04171cfcSAugustin Cavalier if (rsnext) { 474*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(rn, ni, rsnext); 475*04171cfcSAugustin Cavalier rn->probing |= IEEE80211_RA_PROBING_INTER; 476*04171cfcSAugustin Cavalier } else 477*04171cfcSAugustin Cavalier rn->probing &= ~IEEE80211_RA_PROBING_INTER; 478*04171cfcSAugustin Cavalier } 479*04171cfcSAugustin Cavalier 480*04171cfcSAugustin Cavalier int 481*04171cfcSAugustin Cavalier ieee80211_ra_inter_mode_ra_finished(struct ieee80211_ra_node *rn, 482*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 483*04171cfcSAugustin Cavalier { 484*04171cfcSAugustin Cavalier return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0); 485*04171cfcSAugustin Cavalier } 486*04171cfcSAugustin Cavalier 487*04171cfcSAugustin Cavalier int 488*04171cfcSAugustin Cavalier ieee80211_ra_best_rate(struct ieee80211_ra_node *rn, 489*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 490*04171cfcSAugustin Cavalier { 491*04171cfcSAugustin Cavalier int i, best = rn->best_mcs; 492*04171cfcSAugustin Cavalier uint64_t gmax = rn->g[rn->best_mcs].measured; 493*04171cfcSAugustin Cavalier 494*04171cfcSAugustin Cavalier for (i = 0; i < nitems(rn->g); i++) { 495*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[i]; 496*04171cfcSAugustin Cavalier if (((1 << i) & rn->valid_rates) == 0) 497*04171cfcSAugustin Cavalier continue; 498*04171cfcSAugustin Cavalier if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) { 499*04171cfcSAugustin Cavalier gmax = g->measured; 500*04171cfcSAugustin Cavalier best = i; 501*04171cfcSAugustin Cavalier } 502*04171cfcSAugustin Cavalier } 503*04171cfcSAugustin Cavalier 504*04171cfcSAugustin Cavalier #ifdef RA_DEBUG 505*04171cfcSAugustin Cavalier if (rn->best_mcs != best) { 506*04171cfcSAugustin Cavalier DPRINTF(("MCS %d is best; MCS{cur|avg|loss}:", best)); 507*04171cfcSAugustin Cavalier for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { 508*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[i]; 509*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << i)) == 0) 510*04171cfcSAugustin Cavalier continue; 511*04171cfcSAugustin Cavalier DPRINTF((" %d{%s|", i, ra_fp_sprintf(g->measured))); 512*04171cfcSAugustin Cavalier DPRINTF(("%s|", ra_fp_sprintf(g->average))); 513*04171cfcSAugustin Cavalier DPRINTF(("%s%%}", ra_fp_sprintf(g->loss))); 514*04171cfcSAugustin Cavalier } 515*04171cfcSAugustin Cavalier DPRINTF(("\n")); 516*04171cfcSAugustin Cavalier } 517*04171cfcSAugustin Cavalier #endif 518*04171cfcSAugustin Cavalier return best; 519*04171cfcSAugustin Cavalier } 520*04171cfcSAugustin Cavalier 521*04171cfcSAugustin Cavalier void 522*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rate(struct ieee80211_ra_node *rn, 523*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 524*04171cfcSAugustin Cavalier { 525*04171cfcSAugustin Cavalier /* Select the next rate to probe. */ 526*04171cfcSAugustin Cavalier rn->probed_rates |= (1 << ni->ni_txmcs); 527*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ni); 528*04171cfcSAugustin Cavalier } 529*04171cfcSAugustin Cavalier 530*04171cfcSAugustin Cavalier int 531*04171cfcSAugustin Cavalier ieee80211_ra_valid_tx_mcs(struct ieee80211com *ic, int mcs) 532*04171cfcSAugustin Cavalier { 533*04171cfcSAugustin Cavalier uint32_t ntxstreams = 1; 534*04171cfcSAugustin Cavalier static const int max_mcs[] = { 7, 15, 23, 31 }; 535*04171cfcSAugustin Cavalier 536*04171cfcSAugustin Cavalier if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0) 537*04171cfcSAugustin Cavalier return isset(ic->ic_sup_mcs, mcs); 538*04171cfcSAugustin Cavalier 539*04171cfcSAugustin Cavalier ntxstreams += ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2); 540*04171cfcSAugustin Cavalier if (ntxstreams < 1 || ntxstreams > 4) 541*04171cfcSAugustin Cavalier panic("invalid number of Tx streams: %u", ntxstreams); 542*04171cfcSAugustin Cavalier return (mcs <= max_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs)); 543*04171cfcSAugustin Cavalier } 544*04171cfcSAugustin Cavalier 545*04171cfcSAugustin Cavalier uint32_t 546*04171cfcSAugustin Cavalier ieee80211_ra_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni) 547*04171cfcSAugustin Cavalier { 548*04171cfcSAugustin Cavalier uint32_t valid_mcs = 0; 549*04171cfcSAugustin Cavalier int i; 550*04171cfcSAugustin Cavalier 551*04171cfcSAugustin Cavalier for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { 552*04171cfcSAugustin Cavalier if (!isset(ni->ni_rxmcs, i)) 553*04171cfcSAugustin Cavalier continue; 554*04171cfcSAugustin Cavalier if (!ieee80211_ra_valid_tx_mcs(ic, i)) 555*04171cfcSAugustin Cavalier continue; 556*04171cfcSAugustin Cavalier valid_mcs |= (1 << i); 557*04171cfcSAugustin Cavalier } 558*04171cfcSAugustin Cavalier 559*04171cfcSAugustin Cavalier return valid_mcs; 560*04171cfcSAugustin Cavalier } 561*04171cfcSAugustin Cavalier 562*04171cfcSAugustin Cavalier int 563*04171cfcSAugustin Cavalier ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats *g) 564*04171cfcSAugustin Cavalier { 565*04171cfcSAugustin Cavalier /* 128 packets make up a valid probe in any case. */ 566*04171cfcSAugustin Cavalier if (g->nprobe_pkts >= 128) 567*04171cfcSAugustin Cavalier return 1; 568*04171cfcSAugustin Cavalier 569*04171cfcSAugustin Cavalier /* 8 packets with > 75% loss make a valid probe, too. */ 570*04171cfcSAugustin Cavalier if (g->nprobe_pkts >= 8 && 571*04171cfcSAugustin Cavalier g->nprobe_pkts - g->nprobe_fail < g->nprobe_pkts / 4) 572*04171cfcSAugustin Cavalier return 1; 573*04171cfcSAugustin Cavalier 574*04171cfcSAugustin Cavalier return 0; 575*04171cfcSAugustin Cavalier } 576*04171cfcSAugustin Cavalier 577*04171cfcSAugustin Cavalier void 578*04171cfcSAugustin Cavalier ieee80211_ra_add_stats_ht(struct ieee80211_ra_node *rn, 579*04171cfcSAugustin Cavalier struct ieee80211com *ic, struct ieee80211_node *ni, 580*04171cfcSAugustin Cavalier int mcs, uint32_t total, uint32_t fail) 581*04171cfcSAugustin Cavalier { 582*04171cfcSAugustin Cavalier static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */ 583*04171cfcSAugustin Cavalier static const uint64_t beta = RA_FP_1 / 4; /* 1/4 = 0.25 */ 584*04171cfcSAugustin Cavalier int s; 585*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g; 586*04171cfcSAugustin Cavalier uint64_t sfer, rate, delta; 587*04171cfcSAugustin Cavalier 588*04171cfcSAugustin Cavalier /* 589*04171cfcSAugustin Cavalier * Ignore invalid values. These values may come from hardware 590*04171cfcSAugustin Cavalier * so asserting valid values via panic is not appropriate. 591*04171cfcSAugustin Cavalier */ 592*04171cfcSAugustin Cavalier if (mcs < 0 || mcs >= IEEE80211_HT_RATESET_NUM_MCS) 593*04171cfcSAugustin Cavalier return; 594*04171cfcSAugustin Cavalier if (total == 0) 595*04171cfcSAugustin Cavalier return; 596*04171cfcSAugustin Cavalier 597*04171cfcSAugustin Cavalier s = splnet(); 598*04171cfcSAugustin Cavalier 599*04171cfcSAugustin Cavalier g = &rn->g[mcs]; 600*04171cfcSAugustin Cavalier g->nprobe_pkts += total; 601*04171cfcSAugustin Cavalier g->nprobe_fail += fail; 602*04171cfcSAugustin Cavalier 603*04171cfcSAugustin Cavalier if (!ieee80211_ra_probe_valid(g)) { 604*04171cfcSAugustin Cavalier splx(s); 605*04171cfcSAugustin Cavalier return; 606*04171cfcSAugustin Cavalier } 607*04171cfcSAugustin Cavalier rn->valid_probes |= 1U << mcs; 608*04171cfcSAugustin Cavalier 609*04171cfcSAugustin Cavalier if (g->nprobe_fail > g->nprobe_pkts) { 610*04171cfcSAugustin Cavalier DPRINTF(("%s fail %u > pkts %u\n", 611*04171cfcSAugustin Cavalier ether_sprintf(ni->ni_macaddr), 612*04171cfcSAugustin Cavalier g->nprobe_fail, g->nprobe_pkts)); 613*04171cfcSAugustin Cavalier g->nprobe_fail = g->nprobe_pkts; 614*04171cfcSAugustin Cavalier } 615*04171cfcSAugustin Cavalier 616*04171cfcSAugustin Cavalier sfer = g->nprobe_fail << RA_FP_SHIFT; 617*04171cfcSAugustin Cavalier sfer /= g->nprobe_pkts; 618*04171cfcSAugustin Cavalier g->nprobe_fail = 0; 619*04171cfcSAugustin Cavalier g->nprobe_pkts = 0; 620*04171cfcSAugustin Cavalier 621*04171cfcSAugustin Cavalier rate = ieee80211_ra_get_txrate(mcs, 622*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), 623*04171cfcSAugustin Cavalier ieee80211_ra_use_ht_sgi(ni)); 624*04171cfcSAugustin Cavalier 625*04171cfcSAugustin Cavalier g->loss = sfer * 100; 626*04171cfcSAugustin Cavalier g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate); 627*04171cfcSAugustin Cavalier g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average); 628*04171cfcSAugustin Cavalier g->average += RA_FP_MUL(alpha, g->measured); 629*04171cfcSAugustin Cavalier 630*04171cfcSAugustin Cavalier g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation); 631*04171cfcSAugustin Cavalier if (g->average > g->measured) 632*04171cfcSAugustin Cavalier delta = g->average - g->measured; 633*04171cfcSAugustin Cavalier else 634*04171cfcSAugustin Cavalier delta = g->measured - g->average; 635*04171cfcSAugustin Cavalier g->stddeviation += RA_FP_MUL(beta, delta); 636*04171cfcSAugustin Cavalier 637*04171cfcSAugustin Cavalier splx(s); 638*04171cfcSAugustin Cavalier } 639*04171cfcSAugustin Cavalier 640*04171cfcSAugustin Cavalier void 641*04171cfcSAugustin Cavalier ieee80211_ra_choose(struct ieee80211_ra_node *rn, struct ieee80211com *ic, 642*04171cfcSAugustin Cavalier struct ieee80211_node *ni) 643*04171cfcSAugustin Cavalier { 644*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs]; 645*04171cfcSAugustin Cavalier int s; 646*04171cfcSAugustin Cavalier int chan40 = ieee80211_node_supports_ht_chan40(ni); 647*04171cfcSAugustin Cavalier int sgi = ieee80211_ra_use_ht_sgi(ni); 648*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs, *rsnext; 649*04171cfcSAugustin Cavalier 650*04171cfcSAugustin Cavalier s = splnet(); 651*04171cfcSAugustin Cavalier 652*04171cfcSAugustin Cavalier if (rn->valid_rates == 0) 653*04171cfcSAugustin Cavalier rn->valid_rates = ieee80211_ra_valid_rates(ic, ni); 654*04171cfcSAugustin Cavalier 655*04171cfcSAugustin Cavalier if (rn->probing) { 656*04171cfcSAugustin Cavalier /* Probe another rate or settle at the best rate. */ 657*04171cfcSAugustin Cavalier if (!(rn->valid_probes & (1UL << ni->ni_txmcs))) { 658*04171cfcSAugustin Cavalier splx(s); 659*04171cfcSAugustin Cavalier return; 660*04171cfcSAugustin Cavalier } 661*04171cfcSAugustin Cavalier ieee80211_ra_probe_clear(rn, ni); 662*04171cfcSAugustin Cavalier if (!ieee80211_ra_intra_mode_ra_finished(rn, ni)) { 663*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rate(rn, ni); 664*04171cfcSAugustin Cavalier DPRINTFN(3, ("probing MCS %d\n", ni->ni_txmcs)); 665*04171cfcSAugustin Cavalier } else if (ieee80211_ra_inter_mode_ra_finished(rn, ni)) { 666*04171cfcSAugustin Cavalier rn->best_mcs = ieee80211_ra_best_rate(rn, ni); 667*04171cfcSAugustin Cavalier ni->ni_txmcs = rn->best_mcs; 668*04171cfcSAugustin Cavalier ieee80211_ra_probe_done(rn); 669*04171cfcSAugustin Cavalier } 670*04171cfcSAugustin Cavalier 671*04171cfcSAugustin Cavalier splx(s); 672*04171cfcSAugustin Cavalier return; 673*04171cfcSAugustin Cavalier } else { 674*04171cfcSAugustin Cavalier rn->valid_probes = 0; 675*04171cfcSAugustin Cavalier } 676*04171cfcSAugustin Cavalier 677*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, chan40, sgi); 678*04171cfcSAugustin Cavalier if ((g->measured >> RA_FP_SHIFT) == 0LL || 679*04171cfcSAugustin Cavalier (g->average >= 3 * g->stddeviation && 680*04171cfcSAugustin Cavalier g->measured < g->average - 3 * g->stddeviation)) { 681*04171cfcSAugustin Cavalier /* Channel becomes bad. Probe downwards. */ 682*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_PROBING_DOWN; 683*04171cfcSAugustin Cavalier rn->probed_rates = 0; 684*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->min_mcs) { 685*04171cfcSAugustin Cavalier rsnext = ieee80211_ra_next_rateset(rn, ni); 686*04171cfcSAugustin Cavalier if (rsnext) { 687*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(rn, ni, 688*04171cfcSAugustin Cavalier rsnext); 689*04171cfcSAugustin Cavalier } else { 690*04171cfcSAugustin Cavalier /* Cannot probe further down. */ 691*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING; 692*04171cfcSAugustin Cavalier } 693*04171cfcSAugustin Cavalier } else { 694*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ni); 695*04171cfcSAugustin Cavalier rn->candidate_rates = (1 << ni->ni_txmcs); 696*04171cfcSAugustin Cavalier } 697*04171cfcSAugustin Cavalier } else if (g->loss < 2 * RA_FP_1 || 698*04171cfcSAugustin Cavalier g->measured > g->average + 3 * g->stddeviation) { 699*04171cfcSAugustin Cavalier /* Channel becomes good. */ 700*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_PROBING_UP; 701*04171cfcSAugustin Cavalier rn->probed_rates = 0; 702*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->max_mcs) { 703*04171cfcSAugustin Cavalier rsnext = ieee80211_ra_next_rateset(rn, ni); 704*04171cfcSAugustin Cavalier if (rsnext) { 705*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(rn, ni, 706*04171cfcSAugustin Cavalier rsnext); 707*04171cfcSAugustin Cavalier } else { 708*04171cfcSAugustin Cavalier /* Cannot probe further up. */ 709*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING; 710*04171cfcSAugustin Cavalier } 711*04171cfcSAugustin Cavalier } else { 712*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ni); 713*04171cfcSAugustin Cavalier rn->candidate_rates = (1 << ni->ni_txmcs); 714*04171cfcSAugustin Cavalier } 715*04171cfcSAugustin Cavalier } else { 716*04171cfcSAugustin Cavalier /* Remain at current rate. */ 717*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING; 718*04171cfcSAugustin Cavalier rn->probed_rates = 0; 719*04171cfcSAugustin Cavalier rn->candidate_rates = 0; 720*04171cfcSAugustin Cavalier } 721*04171cfcSAugustin Cavalier 722*04171cfcSAugustin Cavalier splx(s); 723*04171cfcSAugustin Cavalier 724*04171cfcSAugustin Cavalier if (rn->probing) { 725*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_UP) 726*04171cfcSAugustin Cavalier DPRINTFN(2, ("channel becomes good; probe up\n")); 727*04171cfcSAugustin Cavalier else 728*04171cfcSAugustin Cavalier DPRINTFN(2, ("channel becomes bad; probe down\n")); 729*04171cfcSAugustin Cavalier 730*04171cfcSAugustin Cavalier DPRINTFN(3, ("measured: %s Mbit/s\n", 731*04171cfcSAugustin Cavalier ra_fp_sprintf(g->measured))); 732*04171cfcSAugustin Cavalier DPRINTFN(3, ("average: %s Mbit/s\n", 733*04171cfcSAugustin Cavalier ra_fp_sprintf(g->average))); 734*04171cfcSAugustin Cavalier DPRINTFN(3, ("stddeviation: %s\n", 735*04171cfcSAugustin Cavalier ra_fp_sprintf(g->stddeviation))); 736*04171cfcSAugustin Cavalier DPRINTFN(3, ("loss: %s%%\n", ra_fp_sprintf(g->loss))); 737*04171cfcSAugustin Cavalier } 738*04171cfcSAugustin Cavalier } 739*04171cfcSAugustin Cavalier 740*04171cfcSAugustin Cavalier void 741*04171cfcSAugustin Cavalier ieee80211_ra_node_init(struct ieee80211_ra_node *rn) 742*04171cfcSAugustin Cavalier { 743*04171cfcSAugustin Cavalier memset(rn, 0, sizeof(*rn)); 744*04171cfcSAugustin Cavalier } 745