1 /* $OpenBSD: ieee80211_ra_vht.c,v 1.3 2022/03/23 09:21:47 stsp Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Christian Ehrhardt <ehrhardt@genua.de> 5 * Copyright (c) 2016, 2021, 2022 Stefan Sperling <stsp@openbsd.org> 6 * Copyright (c) 2016 Theo Buehler <tb@openbsd.org> 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_ra_vht.h> 33 34 int ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *, 35 struct ieee80211_node *); 36 const struct ieee80211_vht_rateset * ieee80211_ra_vht_next_rateset( 37 struct ieee80211_ra_vht_node *, struct ieee80211_node *); 38 int ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *, 39 const struct ieee80211_vht_rateset *); 40 void ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *, 41 struct ieee80211_node *, const struct ieee80211_vht_rateset *); 42 int ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *, 43 struct ieee80211_node *); 44 void ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *, int); 45 int ieee80211_ra_vht_intra_mode_ra_finished( 46 struct ieee80211_ra_vht_node *, struct ieee80211_node *); 47 void ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *, 48 struct ieee80211_node *); 49 int ieee80211_ra_vht_inter_mode_ra_finished( 50 struct ieee80211_ra_vht_node *, struct ieee80211_node *); 51 void ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *, 52 struct ieee80211_node *); 53 void ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *, 54 struct ieee80211_node *); 55 void ieee80211_ra_vht_init_valid_rates(struct ieee80211com *, 56 struct ieee80211_node *, struct ieee80211_ra_vht_node *); 57 int ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats *); 58 59 /* We use fixed point arithmetic with 64 bit integers. */ 60 #define RA_FP_SHIFT 21 61 #define RA_FP_INT(x) (x ## ULL << RA_FP_SHIFT) /* the integer x */ 62 #define RA_FP_1 RA_FP_INT(1) 63 64 /* Multiply two fixed point numbers. */ 65 #define RA_FP_MUL(a, b) \ 66 (((a) * (b)) >> RA_FP_SHIFT) 67 68 /* Divide two fixed point numbers. */ 69 #define RA_FP_DIV(a, b) \ 70 (b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT) / (b))) 71 72 #ifdef RA_DEBUG 73 #define DPRINTF(x) do { if (ra_vht_debug > 0) printf x; } while (0) 74 #define DPRINTFN(n, x) do { if (ra_vht_debug >= (n)) printf x; } while (0) 75 int ra_vht_debug = 0; 76 #else 77 #define DPRINTF(x) do { ; } while (0) 78 #define DPRINTFN(n, x) do { ; } while (0) 79 #endif 80 81 #ifdef RA_DEBUG 82 void 83 ra_vht_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp) 84 { 85 uint64_t tmp; 86 87 /* integer part */ 88 *i = (fp >> RA_FP_SHIFT); 89 90 /* fractional part */ 91 tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT))); 92 tmp *= 100; 93 *f = (uint32_t)(tmp >> RA_FP_SHIFT); 94 } 95 96 char * 97 ra_vht_fp_sprintf(uint64_t fp) 98 { 99 uint32_t i, f; 100 static char buf[64]; 101 int ret; 102 103 ra_vht_fixedp_split(&i, &f, fp); 104 ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f); 105 if (ret == -1 || ret >= sizeof(buf)) 106 return "ERR"; 107 108 return buf; 109 } 110 #endif /* RA_DEBUG */ 111 112 const struct ieee80211_vht_rateset * 113 ieee80211_ra_vht_get_rateset(int mcs, int nss, int chan40, int chan80, int sgi) 114 { 115 const struct ieee80211_vht_rateset *rs; 116 int i; 117 118 for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) { 119 rs = &ieee80211_std_ratesets_11ac[i]; 120 if (mcs < rs->nrates && rs->num_ss == nss && 121 chan40 == rs->chan40 && chan80 == rs->chan80 && 122 sgi == rs->sgi) 123 return rs; 124 } 125 126 panic("MCS %d NSS %d is not part of any rateset", mcs, nss); 127 } 128 129 int 130 ieee80211_ra_vht_use_sgi(struct ieee80211_node *ni) 131 { 132 if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_160MHZ) && 133 ieee80211_node_supports_vht_chan160(ni)) { 134 if (ni->ni_flags & IEEE80211_NODE_VHT_SGI160) 135 return 1; 136 } 137 138 if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_80MHZ) && 139 ieee80211_node_supports_vht_chan80(ni)) { 140 if (ni->ni_flags & IEEE80211_NODE_VHT_SGI80) 141 return 1; 142 } 143 144 return 0; 145 } 146 147 /* 148 * Update goodput statistics. 149 */ 150 151 uint64_t 152 ieee80211_ra_vht_get_txrate(int mcs, int nss, int chan40, int chan80, int sgi) 153 { 154 const struct ieee80211_vht_rateset *rs; 155 uint64_t txrate; 156 157 rs = ieee80211_ra_vht_get_rateset(mcs, nss, chan40, chan80, sgi); 158 txrate = rs->rates[mcs]; 159 txrate <<= RA_FP_SHIFT; /* convert to fixed-point */ 160 txrate *= 500; /* convert to kbit/s */ 161 txrate /= 1000; /* convert to mbit/s */ 162 163 return txrate; 164 } 165 166 /* 167 * Rate selection. 168 */ 169 170 /* A rate's goodput has to be at least this much larger to be "better". */ 171 #define IEEE80211_RA_RATE_THRESHOLD (RA_FP_1 / 64) /* ~ 0.015 */ 172 173 int 174 ieee80211_ra_vht_next_lower_intra_rate(struct ieee80211_ra_vht_node *rn, 175 struct ieee80211_node *ni) 176 { 177 if (ni->ni_txmcs <= 0) 178 return 0; 179 180 return ni->ni_txmcs - 1; 181 } 182 183 int 184 ieee80211_ra_vht_get_max_mcs(int vht_mcs, int nss, int chan40) 185 { 186 int supp_mcs = (vht_mcs & IEEE80211_VHT_MCS_FOR_SS_MASK(nss)) >> 187 IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss); 188 int max_mcs = -1; 189 190 switch (supp_mcs) { 191 case IEEE80211_VHT_MCS_SS_NOT_SUPP: 192 break; 193 case IEEE80211_VHT_MCS_0_7: 194 max_mcs = 7; 195 break; 196 case IEEE80211_VHT_MCS_0_8: 197 max_mcs = 8; 198 break; 199 case IEEE80211_VHT_MCS_0_9: 200 /* Disable VHT MCS 9 for 20MHz-only stations. */ 201 if (!chan40) 202 max_mcs = 8; 203 else 204 max_mcs = 9; 205 break; 206 default: 207 /* Should not happen; Values above cover the possible range. */ 208 panic("invalid VHT Rx MCS value %u", supp_mcs); 209 } 210 211 return max_mcs; 212 } 213 214 int 215 ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *rn, 216 struct ieee80211_node *ni) 217 { 218 int max_mcs; 219 220 max_mcs = ieee80211_ra_vht_get_max_mcs(ni->ni_vht_rxmcs, 221 ni->ni_vht_ss, ieee80211_node_supports_ht_chan40(ni)); 222 if (max_mcs != 7 && max_mcs != 8 && max_mcs != 9) 223 panic("ni->ni_vht_ss invalid: %u", ni->ni_vht_ss); 224 225 if (ni->ni_txmcs >= max_mcs) 226 return max_mcs; 227 228 return ni->ni_txmcs + 1; 229 } 230 231 const struct ieee80211_vht_rateset * 232 ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_node *rn, 233 struct ieee80211_node *ni) 234 { 235 const struct ieee80211_vht_rateset *rs, *rsnext; 236 int next; 237 int sgi = ieee80211_ra_vht_use_sgi(ni); 238 int mcs = ni->ni_txmcs; 239 int nss = ni->ni_vht_ss; 240 241 /* 242 * We only probe 80MHz ratesets. 243 * Drivers handle retries on slower rates if needed. 244 */ 245 rs = ieee80211_ra_vht_get_rateset(mcs, nss, 0, 1, sgi); 246 if (rn->probing & IEEE80211_RA_PROBING_UP) { 247 switch (rs->idx) { 248 case IEEE80211_VHT_RATESET_SISO_80: 249 next = IEEE80211_VHT_RATESET_MIMO2_80; 250 break; 251 case IEEE80211_VHT_RATESET_SISO_80_SGI: 252 next = IEEE80211_VHT_RATESET_MIMO2_80_SGI; 253 break; 254 default: 255 return NULL; 256 } 257 } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) { 258 switch (rs->idx) { 259 case IEEE80211_VHT_RATESET_MIMO2_80: 260 next = IEEE80211_VHT_RATESET_SISO_80; 261 break; 262 case IEEE80211_VHT_RATESET_MIMO2_80_SGI: 263 next = IEEE80211_VHT_RATESET_SISO_80_SGI; 264 break; 265 default: 266 return NULL; 267 } 268 } else 269 panic("%s: invalid probing mode %d", __func__, rn->probing); 270 271 rsnext = &ieee80211_std_ratesets_11ac[next]; 272 if (rn->valid_rates[rsnext->num_ss - 1] == 0) 273 return NULL; 274 275 return rsnext; 276 } 277 278 int 279 ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *rn, 280 const struct ieee80211_vht_rateset *rs) 281 { 282 uint64_t gmax = 0; 283 int mcs, best_mcs = 0; 284 285 for (mcs = 0; mcs < rs->nrates; mcs++) { 286 struct ieee80211_ra_vht_goodput_stats *g = &rn->g[rs->idx][mcs]; 287 if (((1 << mcs) & rn->valid_rates[rs->num_ss - 1]) == 0) 288 continue; 289 if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) { 290 gmax = g->measured; 291 best_mcs = mcs; 292 } 293 } 294 295 return best_mcs; 296 } 297 298 void 299 ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *rn, 300 struct ieee80211_node *ni, const struct ieee80211_vht_rateset *rsnext) 301 { 302 const struct ieee80211_vht_rateset *rs; 303 struct ieee80211_ra_vht_goodput_stats *g; 304 int best_mcs, mcs; 305 306 /* Find most recently measured best MCS from the current rateset. */ 307 rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, ni->ni_vht_ss, 0, 1, 308 ieee80211_ra_vht_use_sgi(ni)); 309 best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs); 310 311 /* Switch to the next rateset. */ 312 ni->ni_txmcs = 0; 313 ni->ni_vht_ss = rsnext->num_ss; 314 315 /* Select the lowest rate from the next rateset with loss-free 316 * goodput close to the current best measurement. */ 317 g = &rn->g[rs->idx][best_mcs]; 318 for (mcs = 0; mcs < rsnext->nrates; mcs++) { 319 uint64_t txrate = rsnext->rates[mcs]; 320 321 if ((rn->valid_rates[rsnext->num_ss - 1] & (1 << mcs)) == 0) 322 continue; 323 324 txrate = txrate * 500; /* convert to kbit/s */ 325 txrate <<= RA_FP_SHIFT; /* convert to fixed-point */ 326 txrate /= 1000; /* convert to mbit/s */ 327 328 if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD) { 329 ni->ni_txmcs = mcs; 330 break; 331 } 332 } 333 /* If all rates are lower then the best rate is the closest match. */ 334 if (mcs == rsnext->nrates) 335 ni->ni_txmcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rsnext); 336 337 /* Add rates from the next rateset as candidates. */ 338 rn->candidate_rates[rsnext->num_ss - 1] |= (1 << ni->ni_txmcs); 339 if (rn->probing & IEEE80211_RA_PROBING_UP) { 340 rn->candidate_rates[rsnext->num_ss - 1] |= 341 (1 << ieee80211_ra_vht_next_intra_rate(rn, ni)); 342 } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) { 343 rn->candidate_rates[rsnext->num_ss - 1] |= 344 (1 << ieee80211_ra_vht_next_lower_intra_rate(rn, ni)); 345 } else 346 panic("%s: invalid probing mode %d", __func__, rn->probing); 347 } 348 349 int 350 ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *rn, 351 struct ieee80211_node *ni) 352 { 353 int next; 354 355 if (rn->probing & IEEE80211_RA_PROBING_DOWN) 356 next = ieee80211_ra_vht_next_lower_intra_rate(rn, ni); 357 else if (rn->probing & IEEE80211_RA_PROBING_UP) 358 next = ieee80211_ra_vht_next_intra_rate(rn, ni); 359 else 360 panic("%s: invalid probing mode %d", __func__, rn->probing); 361 362 return next; 363 } 364 365 void 366 ieee80211_ra_vht_probe_clear(struct ieee80211_ra_vht_goodput_stats *g) 367 { 368 g->nprobe_pkts = 0; 369 g->nprobe_fail = 0; 370 } 371 372 void 373 ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *rn, int nss) 374 { 375 rn->probing = IEEE80211_RA_NOT_PROBING; 376 rn->probed_rates[nss - 1] = 0; 377 rn->valid_probes[nss - 1] = 0; 378 rn->candidate_rates[nss - 1] = 0; 379 } 380 381 int 382 ieee80211_ra_vht_intra_mode_ra_finished(struct ieee80211_ra_vht_node *rn, 383 struct ieee80211_node *ni) 384 { 385 const struct ieee80211_vht_rateset *rs; 386 struct ieee80211_ra_vht_goodput_stats *g; 387 int next_mcs, best_mcs; 388 uint64_t next_rate; 389 int nss = ni->ni_vht_ss; 390 int sgi = ieee80211_ra_vht_use_sgi(ni); 391 392 rn->probed_rates[nss - 1] = (rn->probed_rates[nss - 1] | 393 (1 << ni->ni_txmcs)); 394 395 /* Check if the min/max MCS in this rateset has been probed. */ 396 rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi); 397 if (rn->probing & IEEE80211_RA_PROBING_DOWN) { 398 if (ni->ni_txmcs == 0 || 399 rn->probed_rates[nss - 1] & (1 << 0)) { 400 ieee80211_ra_vht_trigger_next_rateset(rn, ni); 401 return 1; 402 } 403 } else if (rn->probing & IEEE80211_RA_PROBING_UP) { 404 if (ni->ni_txmcs == rn->max_mcs[nss - 1] || 405 rn->probed_rates[nss - 1] & (1 << rn->max_mcs[nss - 1])) { 406 ieee80211_ra_vht_trigger_next_rateset(rn, ni); 407 return 1; 408 } 409 } 410 411 /* 412 * Check if the measured goodput is loss-free and better than the 413 * loss-free goodput of the candidate rate. 414 */ 415 next_mcs = ieee80211_ra_vht_next_mcs(rn, ni); 416 if (next_mcs == ni->ni_txmcs) { 417 ieee80211_ra_vht_trigger_next_rateset(rn, ni); 418 return 1; 419 } 420 next_rate = ieee80211_ra_vht_get_txrate(next_mcs, nss, 0, 1, sgi); 421 g = &rn->g[rs->idx][ni->ni_txmcs]; 422 if (g->loss == 0 && 423 g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) { 424 ieee80211_ra_vht_trigger_next_rateset(rn, ni); 425 return 1; 426 } 427 428 /* Check if we had a better measurement at a previously probed MCS. */ 429 best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs); 430 if (best_mcs != ni->ni_txmcs) { 431 if ((rn->probing & IEEE80211_RA_PROBING_UP) && 432 best_mcs < ni->ni_txmcs) { 433 ieee80211_ra_vht_trigger_next_rateset(rn, ni); 434 return 1; 435 } 436 if ((rn->probing & IEEE80211_RA_PROBING_DOWN) && 437 best_mcs > ni->ni_txmcs) { 438 ieee80211_ra_vht_trigger_next_rateset(rn, ni); 439 return 1; 440 } 441 } 442 443 /* Check if all rates in the set of candidate rates have been probed. */ 444 if ((rn->candidate_rates[nss - 1] & rn->probed_rates[nss - 1]) == 445 rn->candidate_rates[nss - 1]) { 446 /* Remain in the current rateset until above checks trigger. */ 447 rn->probing &= ~IEEE80211_RA_PROBING_INTER; 448 return 1; 449 } 450 451 return 0; 452 } 453 454 void 455 ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *rn, 456 struct ieee80211_node *ni) 457 { 458 const struct ieee80211_vht_rateset *rsnext; 459 460 rsnext = ieee80211_ra_vht_next_rateset(rn, ni); 461 if (rsnext) { 462 ieee80211_ra_vht_probe_next_rateset(rn, ni, rsnext); 463 rn->probing |= IEEE80211_RA_PROBING_INTER; 464 } else 465 rn->probing &= ~IEEE80211_RA_PROBING_INTER; 466 } 467 468 int 469 ieee80211_ra_vht_inter_mode_ra_finished(struct ieee80211_ra_vht_node *rn, 470 struct ieee80211_node *ni) 471 { 472 return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0); 473 } 474 475 void 476 ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *rn, 477 struct ieee80211_node *ni) 478 { 479 const struct ieee80211_vht_rateset *rs; 480 int i, j, best_mcs = rn->best_mcs, best_nss = rn->best_nss; 481 uint64_t gmax; 482 483 rs = ieee80211_ra_vht_get_rateset(best_mcs, best_nss, 0, 1, 484 ieee80211_ra_vht_use_sgi(ni)); 485 gmax = rn->g[rs->idx][best_mcs].measured; 486 487 for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) { 488 rs = &ieee80211_std_ratesets_11ac[i]; 489 for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) { 490 struct ieee80211_ra_vht_goodput_stats *g = &rn->g[i][j]; 491 if (((1 << i) & rn->valid_rates[rs->num_ss - 1]) == 0) 492 continue; 493 if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) { 494 gmax = g->measured; 495 best_mcs = j; 496 best_nss = rs->num_ss; 497 } 498 } 499 } 500 501 #ifdef RA_DEBUG 502 if (rn->best_mcs != best_mcs || rn->best_nss != best_nss) { 503 DPRINTF(("MCS,NSS %d,%d is best; MCS,NSS{cur|avg|loss}:", 504 best_mcs, best_nss)); 505 for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) { 506 rs = &ieee80211_std_ratesets_11ac[i]; 507 if (rs->chan80 == 0 || 508 rs->sgi != ieee80211_ra_vht_use_sgi(ni)) 509 continue; 510 for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) { 511 struct ieee80211_ra_vht_goodput_stats *g; 512 g = &rn->g[i][j]; 513 if ((rn->valid_rates[rs->num_ss - 1] & 514 (1 << j)) == 0) 515 continue; 516 DPRINTF((" %d,%d{%s|", j, rs->num_ss, 517 ra_vht_fp_sprintf(g->measured))); 518 DPRINTF(("%s|", ra_vht_fp_sprintf(g->average))); 519 DPRINTF(("%s%%}", ra_vht_fp_sprintf(g->loss))); 520 } 521 } 522 DPRINTF(("\n")); 523 } 524 #endif 525 rn->best_mcs = best_mcs; 526 rn->best_nss = best_nss; 527 } 528 529 void 530 ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *rn, 531 struct ieee80211_node *ni) 532 { 533 /* Select the next rate to probe. */ 534 rn->probed_rates[ni->ni_vht_ss - 1] |= (1 << ni->ni_txmcs); 535 ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni); 536 } 537 538 void 539 ieee80211_ra_vht_init_valid_rates(struct ieee80211com *ic, 540 struct ieee80211_node *ni, struct ieee80211_ra_vht_node *rn) 541 { 542 int nss, ic_max_mcs, ni_max_mcs, max_mcs; 543 544 memset(rn->max_mcs, 0, sizeof(rn->max_mcs)); 545 memset(rn->valid_rates, 0, sizeof(rn->valid_rates)); 546 547 for (nss = 1; nss <= IEEE80211_VHT_NUM_SS; nss++) { 548 ic_max_mcs = ieee80211_ra_vht_get_max_mcs(ic->ic_vht_txmcs, 549 nss, IEEE80211_CHAN_40MHZ_ALLOWED(ic->ic_bss->ni_chan)); 550 ni_max_mcs = ieee80211_ra_vht_get_max_mcs(ni->ni_vht_rxmcs, 551 nss, ieee80211_node_supports_ht_chan40(ni)); 552 if ((ic_max_mcs != 7 && ic_max_mcs != 8 && ic_max_mcs != 9) || 553 (ni_max_mcs != 7 && ni_max_mcs != 8 && ni_max_mcs != 9)) 554 continue; 555 556 max_mcs = MIN(ic_max_mcs, ni_max_mcs); 557 rn->max_mcs[nss - 1] = max_mcs; 558 rn->valid_rates[nss - 1] = ((1 << (max_mcs + 1)) - 1); 559 } 560 } 561 562 int 563 ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats *g) 564 { 565 /* 128 packets make up a valid probe in any case. */ 566 if (g->nprobe_pkts >= 128) 567 return 1; 568 569 /* 8 packets with > 75% loss make a valid probe, too. */ 570 if (g->nprobe_pkts >= 8 && 571 g->nprobe_pkts - g->nprobe_fail < g->nprobe_pkts / 4) 572 return 1; 573 574 return 0; 575 } 576 577 void 578 ieee80211_ra_vht_add_stats(struct ieee80211_ra_vht_node *rn, 579 struct ieee80211com *ic, struct ieee80211_node *ni, 580 int mcs, int nss, uint32_t total, uint32_t fail) 581 { 582 static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */ 583 static const uint64_t beta = RA_FP_1 / 4; /* 1/4 = 0.25 */ 584 int s; 585 const struct ieee80211_vht_rateset *rs; 586 struct ieee80211_ra_vht_goodput_stats *g; 587 uint64_t sfer, rate, delta; 588 589 /* 590 * Ignore invalid values. These values may come from hardware 591 * so asserting valid values via panic is not appropriate. 592 */ 593 if (mcs < 0 || mcs >= IEEE80211_VHT_RATESET_MAX_NRATES) 594 return; 595 if (nss <= 0 || nss > IEEE80211_VHT_NUM_SS) 596 return; 597 if (total == 0) 598 return; 599 600 s = splnet(); 601 602 rs = ieee80211_ra_vht_get_rateset(mcs, nss, 0, 1, 603 ieee80211_ra_vht_use_sgi(ni)); 604 g = &rn->g[rs->idx][mcs]; 605 g->nprobe_pkts += total; 606 g->nprobe_fail += fail; 607 608 if (!ieee80211_ra_vht_probe_valid(g)) { 609 splx(s); 610 return; 611 } 612 rn->valid_probes[nss - 1] |= 1U << mcs; 613 614 if (g->nprobe_fail > g->nprobe_pkts) { 615 DPRINTF(("%s fail %u > pkts %u\n", 616 ether_sprintf(ni->ni_macaddr), 617 g->nprobe_fail, g->nprobe_pkts)); 618 g->nprobe_fail = g->nprobe_pkts; 619 } 620 621 sfer = g->nprobe_fail << RA_FP_SHIFT; 622 sfer /= g->nprobe_pkts; 623 g->nprobe_fail = 0; 624 g->nprobe_pkts = 0; 625 626 rate = ieee80211_ra_vht_get_txrate(mcs, nss, 0, 1, 627 ieee80211_ra_vht_use_sgi(ni)); 628 629 g->loss = sfer * 100; 630 g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate); 631 g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average); 632 g->average += RA_FP_MUL(alpha, g->measured); 633 634 g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation); 635 if (g->average > g->measured) 636 delta = g->average - g->measured; 637 else 638 delta = g->measured - g->average; 639 g->stddeviation += RA_FP_MUL(beta, delta); 640 641 splx(s); 642 } 643 644 void 645 ieee80211_ra_vht_choose(struct ieee80211_ra_vht_node *rn, 646 struct ieee80211com *ic, struct ieee80211_node *ni) 647 { 648 struct ieee80211_ra_vht_goodput_stats *g; 649 int s; 650 int sgi = ieee80211_ra_vht_use_sgi(ni); 651 const struct ieee80211_vht_rateset *rs, *rsnext; 652 int nss = ni->ni_vht_ss; 653 654 s = splnet(); 655 656 if (rn->valid_rates[0] == 0) { 657 ieee80211_ra_vht_init_valid_rates(ic, ni, rn); 658 if (rn->valid_rates[0] == 0) 659 panic("VHT not supported"); 660 } 661 662 rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi); 663 g = &rn->g[rs->idx][ni->ni_txmcs]; 664 665 if (rn->probing) { 666 /* Probe another rate or settle at the best rate. */ 667 if (!(rn->valid_probes[nss - 1] & (1UL << ni->ni_txmcs))) { 668 splx(s); 669 return; 670 } 671 ieee80211_ra_vht_probe_clear(g); 672 if (!ieee80211_ra_vht_intra_mode_ra_finished(rn, ni)) { 673 ieee80211_ra_vht_probe_next_rate(rn, ni); 674 DPRINTFN(3, ("probing MCS,NSS %d,%d\n", 675 ni->ni_txmcs, ni->ni_vht_ss)); 676 } else if (ieee80211_ra_vht_inter_mode_ra_finished(rn, ni)) { 677 ieee80211_ra_vht_best_rate(rn, ni); 678 ni->ni_txmcs = rn->best_mcs; 679 ni->ni_vht_ss = rn->best_nss; 680 ieee80211_ra_vht_probe_done(rn, nss); 681 } 682 683 splx(s); 684 return; 685 } else { 686 rn->valid_probes[nss - 1] = 0; 687 } 688 689 690 rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi); 691 if ((g->measured >> RA_FP_SHIFT) == 0LL || 692 (g->average >= 3 * g->stddeviation && 693 g->measured < g->average - 3 * g->stddeviation)) { 694 /* Channel becomes bad. Probe downwards. */ 695 rn->probing = IEEE80211_RA_PROBING_DOWN; 696 rn->probed_rates[nss - 1] = 0; 697 if (ni->ni_txmcs == 0) { 698 rsnext = ieee80211_ra_vht_next_rateset(rn, ni); 699 if (rsnext) { 700 ieee80211_ra_vht_probe_next_rateset(rn, ni, 701 rsnext); 702 } else { 703 /* Cannot probe further down. */ 704 rn->probing = IEEE80211_RA_NOT_PROBING; 705 } 706 } else { 707 ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni); 708 rn->candidate_rates[nss - 1] = (1 << ni->ni_txmcs); 709 } 710 } else if (g->loss < 2 * RA_FP_1 || 711 g->measured > g->average + 3 * g->stddeviation) { 712 /* Channel becomes good. */ 713 rn->probing = IEEE80211_RA_PROBING_UP; 714 rn->probed_rates[nss - 1] = 0; 715 if (ni->ni_txmcs == rn->max_mcs[nss - 1]) { 716 rsnext = ieee80211_ra_vht_next_rateset(rn, ni); 717 if (rsnext) { 718 ieee80211_ra_vht_probe_next_rateset(rn, ni, 719 rsnext); 720 } else { 721 /* Cannot probe further up. */ 722 rn->probing = IEEE80211_RA_NOT_PROBING; 723 } 724 } else { 725 ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni); 726 rn->candidate_rates[nss - 1] = (1 << ni->ni_txmcs); 727 } 728 } else { 729 /* Remain at current rate. */ 730 rn->probing = IEEE80211_RA_NOT_PROBING; 731 rn->probed_rates[nss - 1] = 0; 732 rn->candidate_rates[nss - 1] = 0; 733 } 734 735 splx(s); 736 737 if (rn->probing) { 738 if (rn->probing & IEEE80211_RA_PROBING_UP) 739 DPRINTFN(2, ("channel becomes good; probe up\n")); 740 else 741 DPRINTFN(2, ("channel becomes bad; probe down\n")); 742 743 DPRINTFN(3, ("measured: %s Mbit/s\n", 744 ra_vht_fp_sprintf(g->measured))); 745 DPRINTFN(3, ("average: %s Mbit/s\n", 746 ra_vht_fp_sprintf(g->average))); 747 DPRINTFN(3, ("stddeviation: %s\n", 748 ra_vht_fp_sprintf(g->stddeviation))); 749 DPRINTFN(3, ("loss: %s%%\n", ra_vht_fp_sprintf(g->loss))); 750 } 751 } 752 753 void 754 ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node *rn) 755 { 756 memset(rn, 0, sizeof(*rn)); 757 rn->best_nss = 1; 758 } 759