00001 /* 00002 * Simple 802.11 rate-control algorithm for gPXE. 00003 * 00004 * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License as 00008 * published by the Free Software Foundation; either version 2 of the 00009 * License, or any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, but 00012 * WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00019 */ 00020 00021 FILE_LICENCE ( GPL2_OR_LATER ); 00022 00023 #include <stdlib.h> 00024 #include <gpxe/net80211.h> 00025 00026 /** 00027 * @file 00028 * 00029 * Simple 802.11 rate-control algorithm 00030 */ 00031 00032 /** @page rc80211 Rate control philosophy 00033 * 00034 * We want to maximize our transmission speed, to the extent that we 00035 * can do that without dropping undue numbers of packets. We also 00036 * don't want to take up very much code space, so our algorithm has to 00037 * be pretty simple 00038 * 00039 * When we receive a packet, we know what rate it was transmitted at, 00040 * and whether it had to be retransmitted to get to us. 00041 * 00042 * When we send a packet, we hear back how many times it had to be 00043 * retried to get through, and whether it got through at all. 00044 * 00045 * Indications of TX success are more reliable than RX success, but RX 00046 * information helps us know where to start. 00047 * 00048 * To handle all of this, we keep for each rate and each direction (TX 00049 * and RX separately) some state information for the most recent 00050 * packets on that rate and the number of packets for which we have 00051 * information. The state is a 32-bit unsigned integer in which two 00052 * bits represent a packet: 11 if it went through well, 10 if it went 00053 * through with one retry, 01 if it went through with more than one 00054 * retry, or 00 if it didn't go through at all. We define the 00055 * "goodness" for a particular (rate, direction) combination as the 00056 * sum of all the 2-bit fields, times 33, divided by the number of 00057 * 2-bit fields containing valid information (16 except when we're 00058 * starting out). The number produced is between 0 and 99; we use -1 00059 * for rates with less than 4 RX packets or 1 TX, as an indicator that 00060 * we do not have enough information to rely on them. 00061 * 00062 * In deciding which rates are best, we find the weighted average of 00063 * TX and RX goodness, where the weighting is by number of packets 00064 * with data and TX packets are worth 4 times as much as RX packets. 00065 * The weighted average is called "net goodness" and is also a number 00066 * between 0 and 99. If 3 consecutive packets fail transmission 00067 * outright, we automatically ratchet down the rate; otherwise, we 00068 * switch to the best rate whenever the current rate's goodness falls 00069 * below some threshold, and try increasing our rate when the goodness 00070 * is very high. 00071 * 00072 * This system is optimized for gPXE's style of usage. Because normal 00073 * operation always involves receiving something, we'll make our way 00074 * to the best rate pretty quickly. We tend to follow the lead of the 00075 * sending AP in choosing rates, but we won't use rates for long that 00076 * don't work well for us in transmission. We assume gPXE won't be 00077 * running for long enough that rate patterns will change much, so we 00078 * don't have to keep time counters or the like. And if this doesn't 00079 * work well in practice there are many ways it could be tweaked. 00080 * 00081 * To avoid staying at 1Mbps for a long time, we don't track any 00082 * transmitted packets until we've set our rate based on received 00083 * packets. 00084 */ 00085 00086 /** Two-bit packet status indicator for a packet with no retries */ 00087 #define RC_PKT_OK 0x3 00088 00089 /** Two-bit packet status indicator for a packet with one retry */ 00090 #define RC_PKT_RETRIED_ONCE 0x2 00091 00092 /** Two-bit packet status indicator for a TX packet with multiple retries 00093 * 00094 * It is not possible to tell whether an RX packet had one or multiple 00095 * retries; we rely instead on the fact that failed RX packets won't 00096 * get to us at all, so if we receive a lot of RX packets on a certain 00097 * rate it must be pretty good. 00098 */ 00099 #define RC_PKT_RETRIED_MULTI 0x1 00100 00101 /** Two-bit packet status indicator for a TX packet that was never ACKed 00102 * 00103 * It is not possible to tell whether an RX packet was setn if it 00104 * didn't get through to us, but if we don't see one we won't increase 00105 * the goodness for its rate. This asymmetry is part of why TX packets 00106 * are weighted much more heavily than RX. 00107 */ 00108 #define RC_PKT_FAILED 0x0 00109 00110 /** Number of times to weight TX packets more heavily than RX packets */ 00111 #define RC_TX_FACTOR 4 00112 00113 /** Number of consecutive failed TX packets that cause an automatic rate drop */ 00114 #define RC_TX_EMERG_FAIL 3 00115 00116 /** Minimum net goodness below which we will search for a better rate */ 00117 #define RC_GOODNESS_MIN 85 00118 00119 /** Maximum net goodness above which we will try to increase our rate */ 00120 #define RC_GOODNESS_MAX 95 00121 00122 /** Minimum (num RX + @c RC_TX_FACTOR * num TX) to use a certain rate */ 00123 #define RC_UNCERTAINTY_THRESH 4 00124 00125 /** TX direction */ 00126 #define TX 0 00127 00128 /** RX direction */ 00129 #define RX 1 00130 00131 /** A rate control context */ 00132 struct rc80211_ctx 00133 { 00134 /** Goodness state for each rate, TX and RX */ 00135 u32 goodness[2][NET80211_MAX_RATES]; 00136 00137 /** Number of packets recorded for each rate */ 00138 u8 count[2][NET80211_MAX_RATES]; 00139 00140 /** Indication of whether we've set the device rate yet */ 00141 int started; 00142 00143 /** Counter of all packets sent and received */ 00144 int packets; 00145 }; 00146 00147 /** 00148 * Initialize rate-control algorithm 00149 * 00150 * @v dev 802.11 device 00151 * @ret ctx Rate-control context, to be stored in @c dev->rctl 00152 */ 00153 struct rc80211_ctx * rc80211_init ( struct net80211_device *dev __unused ) 00154 { 00155 struct rc80211_ctx *ret = zalloc ( sizeof ( *ret ) ); 00156 return ret; 00157 } 00158 00159 /** 00160 * Calculate net goodness for a certain rate 00161 * 00162 * @v ctx Rate-control context 00163 * @v rate_idx Index of rate to calculate net goodness for 00164 */ 00165 static int rc80211_calc_net_goodness ( struct rc80211_ctx *ctx, 00166 int rate_idx ) 00167 { 00168 int sum[2], num[2], dir, pkt; 00169 00170 for ( dir = 0; dir < 2; dir++ ) { 00171 u32 good = ctx->goodness[dir][rate_idx]; 00172 00173 num[dir] = ctx->count[dir][rate_idx]; 00174 sum[dir] = 0; 00175 00176 for ( pkt = 0; pkt < num[dir]; pkt++ ) 00177 sum[dir] += ( good >> ( 2 * pkt ) ) & 0x3; 00178 } 00179 00180 if ( ( num[TX] * RC_TX_FACTOR + num[RX] ) < RC_UNCERTAINTY_THRESH ) 00181 return -1; 00182 00183 return ( 33 * ( sum[TX] * RC_TX_FACTOR + sum[RX] ) / 00184 ( num[TX] * RC_TX_FACTOR + num[RX] ) ); 00185 } 00186 00187 /** 00188 * Determine the best rate to switch to and return it 00189 * 00190 * @v dev 802.11 device 00191 * @ret rate_idx Index of the best rate to switch to 00192 */ 00193 static int rc80211_pick_best ( struct net80211_device *dev ) 00194 { 00195 struct rc80211_ctx *ctx = dev->rctl; 00196 int best_net_good = 0, best_rate = -1, i; 00197 00198 for ( i = 0; i < dev->nr_rates; i++ ) { 00199 int net_good = rc80211_calc_net_goodness ( ctx, i ); 00200 00201 if ( net_good > best_net_good || 00202 ( best_net_good > RC_GOODNESS_MIN && 00203 net_good > RC_GOODNESS_MIN ) ) { 00204 best_net_good = net_good; 00205 best_rate = i; 00206 } 00207 } 00208 00209 if ( best_rate >= 0 ) { 00210 int old_good = rc80211_calc_net_goodness ( ctx, dev->rate ); 00211 if ( old_good != best_net_good ) 00212 DBGC ( ctx, "802.11 RC %p switching from goodness " 00213 "%d to %d\n", ctx, old_good, best_net_good ); 00214 00215 ctx->started = 1; 00216 return best_rate; 00217 } 00218 00219 return dev->rate; 00220 } 00221 00222 /** 00223 * Set 802.11 device rate 00224 * 00225 * @v dev 802.11 device 00226 * @v rate_idx Index of rate to switch to 00227 * 00228 * This is a thin wrapper around net80211_set_rate_idx to insert a 00229 * debugging message where appropriate. 00230 */ 00231 static inline void rc80211_set_rate ( struct net80211_device *dev, 00232 int rate_idx ) 00233 { 00234 DBGC ( dev->rctl, "802.11 RC %p changing rate %d->%d Mbps\n", dev->rctl, 00235 dev->rates[dev->rate] / 10, dev->rates[rate_idx] / 10 ); 00236 00237 net80211_set_rate_idx ( dev, rate_idx ); 00238 } 00239 00240 /** 00241 * Check rate-control state and change rate if necessary 00242 * 00243 * @v dev 802.11 device 00244 */ 00245 static void rc80211_maybe_set_new ( struct net80211_device *dev ) 00246 { 00247 struct rc80211_ctx *ctx = dev->rctl; 00248 int net_good; 00249 00250 net_good = rc80211_calc_net_goodness ( ctx, dev->rate ); 00251 00252 if ( ! ctx->started ) { 00253 rc80211_set_rate ( dev, rc80211_pick_best ( dev ) ); 00254 return; 00255 } 00256 00257 if ( net_good < 0 ) /* insufficient data */ 00258 return; 00259 00260 if ( net_good > RC_GOODNESS_MAX && dev->rate + 1 < dev->nr_rates ) { 00261 int higher = rc80211_calc_net_goodness ( ctx, dev->rate + 1 ); 00262 if ( higher > net_good || higher < 0 ) 00263 rc80211_set_rate ( dev, dev->rate + 1 ); 00264 else 00265 rc80211_set_rate ( dev, rc80211_pick_best ( dev ) ); 00266 } 00267 00268 if ( net_good < RC_GOODNESS_MIN ) { 00269 rc80211_set_rate ( dev, rc80211_pick_best ( dev ) ); 00270 } 00271 } 00272 00273 /** 00274 * Update rate-control state 00275 * 00276 * @v dev 802.11 device 00277 * @v direction One of the direction constants TX or RX 00278 * @v rate_idx Index of rate at which packet was sent or received 00279 * @v retries Number of times packet was retried before success 00280 * @v failed If nonzero, the packet failed to get through 00281 */ 00282 static void rc80211_update ( struct net80211_device *dev, int direction, 00283 int rate_idx, int retries, int failed ) 00284 { 00285 struct rc80211_ctx *ctx = dev->rctl; 00286 u32 goodness = ctx->goodness[direction][rate_idx]; 00287 00288 if ( ctx->count[direction][rate_idx] < 16 ) 00289 ctx->count[direction][rate_idx]++; 00290 00291 goodness <<= 2; 00292 if ( failed ) 00293 goodness |= RC_PKT_FAILED; 00294 else if ( retries > 1 ) 00295 goodness |= RC_PKT_RETRIED_MULTI; 00296 else if ( retries ) 00297 goodness |= RC_PKT_RETRIED_ONCE; 00298 else 00299 goodness |= RC_PKT_OK; 00300 00301 ctx->goodness[direction][rate_idx] = goodness; 00302 00303 ctx->packets++; 00304 00305 rc80211_maybe_set_new ( dev ); 00306 } 00307 00308 /** 00309 * Update rate-control state for transmitted packet 00310 * 00311 * @v dev 802.11 device 00312 * @v retries Number of times packet was transmitted before success 00313 * @v rc Return status code for transmission 00314 */ 00315 void rc80211_update_tx ( struct net80211_device *dev, int retries, int rc ) 00316 { 00317 struct rc80211_ctx *ctx = dev->rctl; 00318 00319 if ( ! ctx->started ) 00320 return; 00321 00322 rc80211_update ( dev, TX, dev->rate, retries, rc ); 00323 00324 /* Check if the last RC_TX_EMERG_FAIL packets have all failed */ 00325 if ( ! ( ctx->goodness[TX][dev->rate] & 00326 ( ( 1 << ( 2 * RC_TX_EMERG_FAIL ) ) - 1 ) ) ) { 00327 if ( dev->rate == 0 ) 00328 DBGC ( dev->rctl, "802.11 RC %p saw %d consecutive " 00329 "failed TX, but cannot lower rate any further\n", 00330 dev->rctl, RC_TX_EMERG_FAIL ); 00331 else { 00332 DBGC ( dev->rctl, "802.11 RC %p lowering rate (%d->%d " 00333 "Mbps) due to %d consecutive TX failures\n", 00334 dev->rctl, dev->rates[dev->rate] / 10, 00335 dev->rates[dev->rate - 1] / 10, 00336 RC_TX_EMERG_FAIL ); 00337 00338 rc80211_set_rate ( dev, dev->rate - 1 ); 00339 } 00340 } 00341 } 00342 00343 /** 00344 * Update rate-control state for received packet 00345 * 00346 * @v dev 802.11 device 00347 * @v retry Whether the received packet had been retransmitted 00348 * @v rate Rate at which packet was received, in 100 kbps units 00349 */ 00350 void rc80211_update_rx ( struct net80211_device *dev, int retry, u16 rate ) 00351 { 00352 int ridx; 00353 00354 for ( ridx = 0; ridx < dev->nr_rates && dev->rates[ridx] != rate; 00355 ridx++ ) 00356 ; 00357 if ( ridx >= dev->nr_rates ) 00358 return; /* couldn't find the rate */ 00359 00360 rc80211_update ( dev, RX, ridx, retry, 0 ); 00361 } 00362 00363 /** 00364 * Free rate-control context 00365 * 00366 * @v ctx Rate-control context 00367 */ 00368 void rc80211_free ( struct rc80211_ctx *ctx ) 00369 { 00370 free ( ctx ); 00371 }
1.5.7.1