|
|
1.1 ! root 1: /* ! 2: * Simple 802.11 rate-control algorithm for iPXE. ! 3: * ! 4: * Copyright (c) 2009 Joshua Oreman <[email protected]>. ! 5: * ! 6: * This program is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU General Public License as ! 8: * published by the Free Software Foundation; either version 2 of the ! 9: * License, or any later version. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, but ! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU General Public License ! 17: * along with this program; if not, write to the Free Software ! 18: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 19: */ ! 20: ! 21: FILE_LICENCE ( GPL2_OR_LATER ); ! 22: ! 23: #include <stdlib.h> ! 24: #include <ipxe/net80211.h> ! 25: ! 26: /** ! 27: * @file ! 28: * ! 29: * Simple 802.11 rate-control algorithm ! 30: */ ! 31: ! 32: /** @page rc80211 Rate control philosophy ! 33: * ! 34: * We want to maximize our transmission speed, to the extent that we ! 35: * can do that without dropping undue numbers of packets. We also ! 36: * don't want to take up very much code space, so our algorithm has to ! 37: * be pretty simple ! 38: * ! 39: * When we receive a packet, we know what rate it was transmitted at, ! 40: * and whether it had to be retransmitted to get to us. ! 41: * ! 42: * When we send a packet, we hear back how many times it had to be ! 43: * retried to get through, and whether it got through at all. ! 44: * ! 45: * Indications of TX success are more reliable than RX success, but RX ! 46: * information helps us know where to start. ! 47: * ! 48: * To handle all of this, we keep for each rate and each direction (TX ! 49: * and RX separately) some state information for the most recent ! 50: * packets on that rate and the number of packets for which we have ! 51: * information. The state is a 32-bit unsigned integer in which two ! 52: * bits represent a packet: 11 if it went through well, 10 if it went ! 53: * through with one retry, 01 if it went through with more than one ! 54: * retry, or 00 if it didn't go through at all. We define the ! 55: * "goodness" for a particular (rate, direction) combination as the ! 56: * sum of all the 2-bit fields, times 33, divided by the number of ! 57: * 2-bit fields containing valid information (16 except when we're ! 58: * starting out). The number produced is between 0 and 99; we use -1 ! 59: * for rates with less than 4 RX packets or 1 TX, as an indicator that ! 60: * we do not have enough information to rely on them. ! 61: * ! 62: * In deciding which rates are best, we find the weighted average of ! 63: * TX and RX goodness, where the weighting is by number of packets ! 64: * with data and TX packets are worth 4 times as much as RX packets. ! 65: * The weighted average is called "net goodness" and is also a number ! 66: * between 0 and 99. If 3 consecutive packets fail transmission ! 67: * outright, we automatically ratchet down the rate; otherwise, we ! 68: * switch to the best rate whenever the current rate's goodness falls ! 69: * below some threshold, and try increasing our rate when the goodness ! 70: * is very high. ! 71: * ! 72: * This system is optimized for iPXE's style of usage. Because normal ! 73: * operation always involves receiving something, we'll make our way ! 74: * to the best rate pretty quickly. We tend to follow the lead of the ! 75: * sending AP in choosing rates, but we won't use rates for long that ! 76: * don't work well for us in transmission. We assume iPXE won't be ! 77: * running for long enough that rate patterns will change much, so we ! 78: * don't have to keep time counters or the like. And if this doesn't ! 79: * work well in practice there are many ways it could be tweaked. ! 80: * ! 81: * To avoid staying at 1Mbps for a long time, we don't track any ! 82: * transmitted packets until we've set our rate based on received ! 83: * packets. ! 84: */ ! 85: ! 86: /** Two-bit packet status indicator for a packet with no retries */ ! 87: #define RC_PKT_OK 0x3 ! 88: ! 89: /** Two-bit packet status indicator for a packet with one retry */ ! 90: #define RC_PKT_RETRIED_ONCE 0x2 ! 91: ! 92: /** Two-bit packet status indicator for a TX packet with multiple retries ! 93: * ! 94: * It is not possible to tell whether an RX packet had one or multiple ! 95: * retries; we rely instead on the fact that failed RX packets won't ! 96: * get to us at all, so if we receive a lot of RX packets on a certain ! 97: * rate it must be pretty good. ! 98: */ ! 99: #define RC_PKT_RETRIED_MULTI 0x1 ! 100: ! 101: /** Two-bit packet status indicator for a TX packet that was never ACKed ! 102: * ! 103: * It is not possible to tell whether an RX packet was setn if it ! 104: * didn't get through to us, but if we don't see one we won't increase ! 105: * the goodness for its rate. This asymmetry is part of why TX packets ! 106: * are weighted much more heavily than RX. ! 107: */ ! 108: #define RC_PKT_FAILED 0x0 ! 109: ! 110: /** Number of times to weight TX packets more heavily than RX packets */ ! 111: #define RC_TX_FACTOR 4 ! 112: ! 113: /** Number of consecutive failed TX packets that cause an automatic rate drop */ ! 114: #define RC_TX_EMERG_FAIL 3 ! 115: ! 116: /** Minimum net goodness below which we will search for a better rate */ ! 117: #define RC_GOODNESS_MIN 85 ! 118: ! 119: /** Maximum net goodness above which we will try to increase our rate */ ! 120: #define RC_GOODNESS_MAX 95 ! 121: ! 122: /** Minimum (num RX + @c RC_TX_FACTOR * num TX) to use a certain rate */ ! 123: #define RC_UNCERTAINTY_THRESH 4 ! 124: ! 125: /** TX direction */ ! 126: #define TX 0 ! 127: ! 128: /** RX direction */ ! 129: #define RX 1 ! 130: ! 131: /** A rate control context */ ! 132: struct rc80211_ctx ! 133: { ! 134: /** Goodness state for each rate, TX and RX */ ! 135: u32 goodness[2][NET80211_MAX_RATES]; ! 136: ! 137: /** Number of packets recorded for each rate */ ! 138: u8 count[2][NET80211_MAX_RATES]; ! 139: ! 140: /** Indication of whether we've set the device rate yet */ ! 141: int started; ! 142: ! 143: /** Counter of all packets sent and received */ ! 144: int packets; ! 145: }; ! 146: ! 147: /** ! 148: * Initialize rate-control algorithm ! 149: * ! 150: * @v dev 802.11 device ! 151: * @ret ctx Rate-control context, to be stored in @c dev->rctl ! 152: */ ! 153: struct rc80211_ctx * rc80211_init ( struct net80211_device *dev __unused ) ! 154: { ! 155: struct rc80211_ctx *ret = zalloc ( sizeof ( *ret ) ); ! 156: return ret; ! 157: } ! 158: ! 159: /** ! 160: * Calculate net goodness for a certain rate ! 161: * ! 162: * @v ctx Rate-control context ! 163: * @v rate_idx Index of rate to calculate net goodness for ! 164: */ ! 165: static int rc80211_calc_net_goodness ( struct rc80211_ctx *ctx, ! 166: int rate_idx ) ! 167: { ! 168: int sum[2], num[2], dir, pkt; ! 169: ! 170: for ( dir = 0; dir < 2; dir++ ) { ! 171: u32 good = ctx->goodness[dir][rate_idx]; ! 172: ! 173: num[dir] = ctx->count[dir][rate_idx]; ! 174: sum[dir] = 0; ! 175: ! 176: for ( pkt = 0; pkt < num[dir]; pkt++ ) ! 177: sum[dir] += ( good >> ( 2 * pkt ) ) & 0x3; ! 178: } ! 179: ! 180: if ( ( num[TX] * RC_TX_FACTOR + num[RX] ) < RC_UNCERTAINTY_THRESH ) ! 181: return -1; ! 182: ! 183: return ( 33 * ( sum[TX] * RC_TX_FACTOR + sum[RX] ) / ! 184: ( num[TX] * RC_TX_FACTOR + num[RX] ) ); ! 185: } ! 186: ! 187: /** ! 188: * Determine the best rate to switch to and return it ! 189: * ! 190: * @v dev 802.11 device ! 191: * @ret rate_idx Index of the best rate to switch to ! 192: */ ! 193: static int rc80211_pick_best ( struct net80211_device *dev ) ! 194: { ! 195: struct rc80211_ctx *ctx = dev->rctl; ! 196: int best_net_good = 0, best_rate = -1, i; ! 197: ! 198: for ( i = 0; i < dev->nr_rates; i++ ) { ! 199: int net_good = rc80211_calc_net_goodness ( ctx, i ); ! 200: ! 201: if ( net_good > best_net_good || ! 202: ( best_net_good > RC_GOODNESS_MIN && ! 203: net_good > RC_GOODNESS_MIN ) ) { ! 204: best_net_good = net_good; ! 205: best_rate = i; ! 206: } ! 207: } ! 208: ! 209: if ( best_rate >= 0 ) { ! 210: int old_good = rc80211_calc_net_goodness ( ctx, dev->rate ); ! 211: if ( old_good != best_net_good ) ! 212: DBGC ( ctx, "802.11 RC %p switching from goodness " ! 213: "%d to %d\n", ctx, old_good, best_net_good ); ! 214: ! 215: ctx->started = 1; ! 216: return best_rate; ! 217: } ! 218: ! 219: return dev->rate; ! 220: } ! 221: ! 222: /** ! 223: * Set 802.11 device rate ! 224: * ! 225: * @v dev 802.11 device ! 226: * @v rate_idx Index of rate to switch to ! 227: * ! 228: * This is a thin wrapper around net80211_set_rate_idx to insert a ! 229: * debugging message where appropriate. ! 230: */ ! 231: static inline void rc80211_set_rate ( struct net80211_device *dev, ! 232: int rate_idx ) ! 233: { ! 234: DBGC ( dev->rctl, "802.11 RC %p changing rate %d->%d Mbps\n", dev->rctl, ! 235: dev->rates[dev->rate] / 10, dev->rates[rate_idx] / 10 ); ! 236: ! 237: net80211_set_rate_idx ( dev, rate_idx ); ! 238: } ! 239: ! 240: /** ! 241: * Check rate-control state and change rate if necessary ! 242: * ! 243: * @v dev 802.11 device ! 244: */ ! 245: static void rc80211_maybe_set_new ( struct net80211_device *dev ) ! 246: { ! 247: struct rc80211_ctx *ctx = dev->rctl; ! 248: int net_good; ! 249: ! 250: net_good = rc80211_calc_net_goodness ( ctx, dev->rate ); ! 251: ! 252: if ( ! ctx->started ) { ! 253: rc80211_set_rate ( dev, rc80211_pick_best ( dev ) ); ! 254: return; ! 255: } ! 256: ! 257: if ( net_good < 0 ) /* insufficient data */ ! 258: return; ! 259: ! 260: if ( net_good > RC_GOODNESS_MAX && dev->rate + 1 < dev->nr_rates ) { ! 261: int higher = rc80211_calc_net_goodness ( ctx, dev->rate + 1 ); ! 262: if ( higher > net_good || higher < 0 ) ! 263: rc80211_set_rate ( dev, dev->rate + 1 ); ! 264: else ! 265: rc80211_set_rate ( dev, rc80211_pick_best ( dev ) ); ! 266: } ! 267: ! 268: if ( net_good < RC_GOODNESS_MIN ) { ! 269: rc80211_set_rate ( dev, rc80211_pick_best ( dev ) ); ! 270: } ! 271: } ! 272: ! 273: /** ! 274: * Update rate-control state ! 275: * ! 276: * @v dev 802.11 device ! 277: * @v direction One of the direction constants TX or RX ! 278: * @v rate_idx Index of rate at which packet was sent or received ! 279: * @v retries Number of times packet was retried before success ! 280: * @v failed If nonzero, the packet failed to get through ! 281: */ ! 282: static void rc80211_update ( struct net80211_device *dev, int direction, ! 283: int rate_idx, int retries, int failed ) ! 284: { ! 285: struct rc80211_ctx *ctx = dev->rctl; ! 286: u32 goodness = ctx->goodness[direction][rate_idx]; ! 287: ! 288: if ( ctx->count[direction][rate_idx] < 16 ) ! 289: ctx->count[direction][rate_idx]++; ! 290: ! 291: goodness <<= 2; ! 292: if ( failed ) ! 293: goodness |= RC_PKT_FAILED; ! 294: else if ( retries > 1 ) ! 295: goodness |= RC_PKT_RETRIED_MULTI; ! 296: else if ( retries ) ! 297: goodness |= RC_PKT_RETRIED_ONCE; ! 298: else ! 299: goodness |= RC_PKT_OK; ! 300: ! 301: ctx->goodness[direction][rate_idx] = goodness; ! 302: ! 303: ctx->packets++; ! 304: ! 305: rc80211_maybe_set_new ( dev ); ! 306: } ! 307: ! 308: /** ! 309: * Update rate-control state for transmitted packet ! 310: * ! 311: * @v dev 802.11 device ! 312: * @v retries Number of times packet was transmitted before success ! 313: * @v rc Return status code for transmission ! 314: */ ! 315: void rc80211_update_tx ( struct net80211_device *dev, int retries, int rc ) ! 316: { ! 317: struct rc80211_ctx *ctx = dev->rctl; ! 318: ! 319: if ( ! ctx->started ) ! 320: return; ! 321: ! 322: rc80211_update ( dev, TX, dev->rate, retries, rc ); ! 323: ! 324: /* Check if the last RC_TX_EMERG_FAIL packets have all failed */ ! 325: if ( ! ( ctx->goodness[TX][dev->rate] & ! 326: ( ( 1 << ( 2 * RC_TX_EMERG_FAIL ) ) - 1 ) ) ) { ! 327: if ( dev->rate == 0 ) ! 328: DBGC ( dev->rctl, "802.11 RC %p saw %d consecutive " ! 329: "failed TX, but cannot lower rate any further\n", ! 330: dev->rctl, RC_TX_EMERG_FAIL ); ! 331: else { ! 332: DBGC ( dev->rctl, "802.11 RC %p lowering rate (%d->%d " ! 333: "Mbps) due to %d consecutive TX failures\n", ! 334: dev->rctl, dev->rates[dev->rate] / 10, ! 335: dev->rates[dev->rate - 1] / 10, ! 336: RC_TX_EMERG_FAIL ); ! 337: ! 338: rc80211_set_rate ( dev, dev->rate - 1 ); ! 339: } ! 340: } ! 341: } ! 342: ! 343: /** ! 344: * Update rate-control state for received packet ! 345: * ! 346: * @v dev 802.11 device ! 347: * @v retry Whether the received packet had been retransmitted ! 348: * @v rate Rate at which packet was received, in 100 kbps units ! 349: */ ! 350: void rc80211_update_rx ( struct net80211_device *dev, int retry, u16 rate ) ! 351: { ! 352: int ridx; ! 353: ! 354: for ( ridx = 0; ridx < dev->nr_rates && dev->rates[ridx] != rate; ! 355: ridx++ ) ! 356: ; ! 357: if ( ridx >= dev->nr_rates ) ! 358: return; /* couldn't find the rate */ ! 359: ! 360: rc80211_update ( dev, RX, ridx, retry, 0 ); ! 361: } ! 362: ! 363: /** ! 364: * Free rate-control context ! 365: * ! 366: * @v ctx Rate-control context ! 367: */ ! 368: void rc80211_free ( struct rc80211_ctx *ctx ) ! 369: { ! 370: free ( ctx ); ! 371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.