選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

rc80211.c 11KB

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