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