2 * Copyright (c) 2005 John Bicket
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
15 * 3. Neither the names of the above-listed copyright holders nor the names
16 * of any contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * Alternatively, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") version 2 as published by the Free
21 * Software Foundation.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGES.
36 * $FreeBSD: src/sys/dev/ath/ath_rate/sample/sample.c,v 1.8.2.3 2006/03/14 23:22:27 sam Exp $
37 * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c,v 1.4 2008/01/15 09:01:13 sephe Exp $
41 * John Bicket's SampleRate control algorithm.
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/sysctl.h>
51 #include <net/if_media.h>
52 #include <net/if_arp.h>
54 #include <netproto/802_11/ieee80211_var.h>
55 #include <netproto/802_11/wlan_ratectl/sample/ieee80211_sample_param.h>
60 #define DPRINTF(ssc, lv, fmt, ...) do { \
61 if (ssc->param->sample_debug >= lv) \
62 kprintf(fmt, __VA_ARGS__); \
65 #define DPRINTF(ssc, lv, fmt, ...)
69 struct ieee80211com *ic;
71 struct sysctl_ctx_list sysctl_ctx;
72 struct sysctl_oid *sysctl_oid;
74 struct ieee80211_sample_param *param;
75 #define smoothing_rate param->sample_smoothing_rate
79 unsigned average_tx_time;
80 int successive_failures;
84 unsigned perfect_tx_time; /* transmit time for 0 retries */
88 #define NUM_PACKET_SIZE_BINS 3
94 struct rate_stats stats[NUM_PACKET_SIZE_BINS][IEEE80211_RATE_MAXSIZE];
95 int last_sample_ndx[NUM_PACKET_SIZE_BINS];
97 int current_sample_ndx[NUM_PACKET_SIZE_BINS];
98 int packets_sent[NUM_PACKET_SIZE_BINS];
100 int current_rate[NUM_PACKET_SIZE_BINS];
101 int packets_since_switch[NUM_PACKET_SIZE_BINS];
102 unsigned ticks_since_switch[NUM_PACKET_SIZE_BINS];
104 int packets_since_sample[NUM_PACKET_SIZE_BINS];
105 unsigned sample_tt[NUM_PACKET_SIZE_BINS];
109 * This file is an implementation of the SampleRate algorithm
110 * in "Bit-rate Selection in Wireless Networks"
111 * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
113 * SampleRate chooses the bit-rate it predicts will provide the most
114 * throughput based on estimates of the expected per-packet
115 * transmission time for each bit-rate. SampleRate periodically sends
116 * packets at bit-rates other than the current one to estimate when
117 * another bit-rate will provide better performance. SampleRate
118 * switches to another bit-rate when its estimated per-packet
119 * transmission time becomes smaller than the current bit-rate's.
120 * SampleRate reduces the number of bit-rates it must sample by
121 * eliminating those that could not perform better than the one
122 * currently being used. SampleRate also stops probing at a bit-rate
123 * if it experiences several successive losses.
125 * The difference between the algorithm in the thesis and the one in this
126 * file is that the one in this file uses a ewma instead of a window.
128 * Also, this implementation tracks the average transmission time for
129 * a few different packet sizes independently for each link.
132 #define STALE_FAILURE_TIMEOUT_MS 10000
133 #define MIN_SWITCH_MS 1000
135 static void *sample_attach(struct ieee80211com *);
136 static void sample_detach(void *);
137 static void sample_data_alloc(struct ieee80211_node *);
138 static void sample_data_free(struct ieee80211_node *);
139 static void sample_data_dup(const struct ieee80211_node *,
140 struct ieee80211_node *);
141 static void sample_newstate(void *, enum ieee80211_state);
142 static void sample_tx_complete(void *, struct ieee80211_node *, int,
143 const struct ieee80211_ratectl_res[],
145 static void sample_newassoc(void *, struct ieee80211_node *, int);
146 static int sample_findrate(void *, struct ieee80211_node *, int,
149 static void sample_sysctl_attach(struct sample_softc *);
150 static void sample_start(struct sample_softc *, struct ieee80211_node *);
151 static void sample_update_stats(struct sample_softc *,
152 struct ieee80211_node *, int, int,
153 const struct ieee80211_ratectl_res [], int,
156 static const struct ieee80211_ratectl sample = {
158 .rc_ratectl = IEEE80211_RATECTL_SAMPLE,
159 .rc_attach = sample_attach,
160 .rc_detach = sample_detach,
161 .rc_data_alloc = sample_data_alloc,
162 .rc_data_free = sample_data_free,
163 .rc_data_dup = sample_data_dup,
164 .rc_newstate = sample_newstate,
165 .rc_tx_complete = sample_tx_complete,
166 .rc_newassoc = sample_newassoc,
167 .rc_findrate = sample_findrate
170 static u_int sample_nrefs;
173 * for now, we track performance for three different packet
176 static int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600, 3000 };
178 MALLOC_DEFINE(M_SAMPLE_RATECTL_DATA, "sample_ratectl_data",
179 "sample rate control data");
182 size_to_bin(int size)
186 for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) {
187 if (size <= packet_size_bins[x])
190 return NUM_PACKET_SIZE_BINS - 1;
194 bin_to_size(int index)
196 return packet_size_bins[index];
200 rate_to_ndx(struct ieee80211_node *ni, int rate)
204 for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
205 if (IEEE80211_RS_RATE(&ni->ni_rates, x) == rate)
212 unicast_pkt_time(struct sample_softc *ssc, struct ieee80211_node *ni,
213 int rate, int len, int data_tries, int rts_tries,
216 struct ieee80211com *ic = ssc->ic;
217 int sifs, difs, slot;
218 int ack_dur, data_dur, cw;
222 ack_dur = ieee80211_txtime(ni,
223 sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN,
224 ieee80211_ack_rate(ni, rate), ic->ic_flags);
225 data_dur = ieee80211_txtime(ni, len, rate, ic->ic_flags);
227 if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) {
228 cw = IEEE80211_CW_MIN_1;
229 sifs = IEEE80211_DUR_OFDM_SIFS;
230 slot = IEEE80211_DUR_OFDM_SLOT;
232 /* XXX should base on characteristic rate set */
233 cw = IEEE80211_CW_MIN_0;
234 sifs = IEEE80211_DUR_SIFS;
235 slot = (ic->ic_flags & IEEE80211_F_SHSLOT)
236 ? IEEE80211_DUR_SHSLOT
237 : IEEE80211_DUR_SLOT;
239 if (cw0 != NULL && *cw0 != 0)
241 difs = IEEE80211_DUR_DIFS(sifs, slot);
243 if (rts_tries > 0 && (ic->ic_flags & IEEE80211_F_USEPROT) &&
244 ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) {
245 if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
247 int rts_dur, cts_dur;
249 /* Assume RTS is sent at 2Mbits/s */
252 rts_dur = ieee80211_txtime(ni,
253 sizeof(struct ieee80211_frame_rts) +
255 rts_rate, ic->ic_flags);
256 cts_dur = ieee80211_txtime(ni,
257 sizeof(struct ieee80211_frame_cts) +
259 ieee80211_ack_rate(ni, rts_rate),
262 tt += rts_tries * (rts_dur + sifs + cts_dur);
265 * Immediate data transmission does not perform backoff
268 * XXX not correct, if RTS retries (short retry count)
269 * reaches dot11ShortRetryLimit, which should be rare.
273 } else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
274 /* Assume CTS is sent at 2Mbits/s */
275 tt += ieee80211_txtime(ni,
276 sizeof(struct ieee80211_frame_cts) +
286 tt += data_tries * (data_dur + sifs + ack_dur);
288 /* Average time consumed by backoff procedure */
289 for (i = 0; i < (data_tries + rts_tries); ++i) {
290 tt += difs + (slot * cw / 2);
291 cw = MIN(IEEE80211_CW_MAX + 1, (cw + 1) * 2) - 1;
299 * returns the ndx with the lowest average_tx_time,
300 * or -1 if all the average_tx_times are 0.
303 best_rate_ndx(struct ieee80211_node *ni, int size_bin,
304 int require_acked_before)
306 int x, best_rate_ndx = 0, best_rate_tt = 0;
307 struct sample_data *sd = ni->ni_rate_data;
309 for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
310 int tt = sd->stats[size_bin][x].average_tx_time;
313 (require_acked_before &&
314 !sd->stats[size_bin][x].packets_acked))
317 /* 9 megabits never works better than 12 */
318 if (IEEE80211_RS_RATE(&ni->ni_rates, x) == 18)
321 /* don't use a bit-rate that has been failing */
322 if (sd->stats[size_bin][x].successive_failures > 3)
325 if (!best_rate_tt || best_rate_tt > tt) {
330 return (best_rate_tt) ? best_rate_ndx : -1;
334 * pick a good "random" bit-rate to sample other than the current one
337 pick_sample_ndx(struct ieee80211_node *ni, int size_bin)
341 unsigned current_tt = 0;
342 struct sample_data *sd = ni->ni_rate_data;
344 current_ndx = sd->current_rate[size_bin];
345 if (current_ndx < 0) {
346 /* no successes yet, send at the lowest bit-rate */
350 current_tt = sd->stats[size_bin][current_ndx].average_tx_time;
352 for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
353 int ndx = (sd->last_sample_ndx[size_bin] + 1 + x) %
354 ni->ni_rates.rs_nrates;
356 /* don't sample the current bit-rate */
357 if (ndx == current_ndx)
360 /* this bit-rate is always worse than the current one */
361 if (sd->stats[size_bin][ndx].perfect_tx_time > current_tt)
364 /* rarely sample bit-rates that fail a lot */
365 if (ticks - sd->stats[size_bin][ndx].last_tx < ((hz * STALE_FAILURE_TIMEOUT_MS) / 1000) &&
366 sd->stats[size_bin][ndx].successive_failures > 3)
370 * don't sample more than 2 indexes higher
371 * for rates higher than 11 megabits
373 if (IEEE80211_RS_RATE(&ni->ni_rates, ndx) > 22 &&
374 ndx > current_ndx + 2)
377 /* 9 megabits never works better than 12 */
378 if (IEEE80211_RS_RATE(&ni->ni_rates, ndx) == 18)
382 * if we're using 11 megabits, only sample up to 12 megabits
384 if (IEEE80211_RS_RATE(&ni->ni_rates, current_ndx) == 22 &&
385 ndx > current_ndx + 1)
388 sd->last_sample_ndx[size_bin] = ndx;
395 sample_findrate(void *arg, struct ieee80211_node *ni, int frame_len,
396 int rateidx[], int rateidx_len)
398 struct sample_softc *ssc = arg;
399 struct sample_data *sd = ni->ni_rate_data;
400 struct ieee80211com *ic = ssc->ic;
401 struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
402 int ndx, size_bin, best_ndx, change_rates, ack_before, cur_ndx, i;
403 unsigned average_tx_time;
408 * This could happen on a "reclaimed" node, which will
409 * vanish soon, so don't bother to call sample_start()
415 for (i = 0; i < NUM_PACKET_SIZE_BINS; ++i) {
416 if (sd->current_rate[i] >= ni->ni_rates.rs_nrates) {
417 DPRINTF(ssc, 5, "%s: number of rates changed, "
418 "restart\n", __func__);
419 sample_start(ssc, ni);
425 KKASSERT(frame_len > 0);
426 size_bin = size_to_bin(frame_len);
428 ack_before = (!(rc_st->rc_st_flags & IEEE80211_RATECTL_F_MRR) ||
429 (ic->ic_flags & IEEE80211_F_USEPROT));
430 best_ndx = best_rate_ndx(ni, size_bin, ack_before);
432 average_tx_time = sd->stats[size_bin][best_ndx].average_tx_time;
436 if (sd->static_rate_ndx != -1) {
437 ndx = sd->static_rate_ndx;
439 if (sd->sample_tt[size_bin] <
440 average_tx_time * (sd->packets_since_sample[size_bin] * ssc->param->sample_rate / 100)) {
442 * We want to limit the time measuring the
443 * performance of other bit-rates to sample_rate%
444 * of the total transmission time.
446 ndx = pick_sample_ndx(ni, size_bin);
447 if (ndx != sd->current_rate[size_bin])
448 sd->current_sample_ndx[size_bin] = ndx;
450 sd->current_sample_ndx[size_bin] = -1;
451 sd->packets_since_sample[size_bin] = 0;
454 if (!sd->packets_sent[size_bin] || best_ndx == -1) {
455 /* no packet has been sent successfully yet */
456 for (ndx = ni->ni_rates.rs_nrates - 1; ndx > 0; ndx--) {
458 * pick the highest rate <= 36 Mbps
459 * that hasn't failed.
461 if (IEEE80211_RS_RATE(&ni->ni_rates, ndx) <= 72 &&
462 sd->stats[size_bin][ndx].successive_failures == 0)
467 } else if (sd->packets_sent[size_bin] < 20) {
468 /* let the bit-rate switch quickly during the first few packets */
470 } else if (ticks - ((hz * MIN_SWITCH_MS) / 1000) > sd->ticks_since_switch[size_bin]) {
471 /* 2 seconds have gone by */
473 } else if (average_tx_time * 2 < sd->stats[size_bin][sd->current_rate[size_bin]].average_tx_time) {
474 /* the current bit-rate is twice as slow as the best one */
478 sd->packets_since_sample[size_bin]++;
481 if (best_ndx != sd->current_rate[size_bin]) {
482 DPRINTF(ssc, 5, "%s: %6D size %d "
484 "%d (%d/%d) -> %d (%d/%d) "
485 "after %d packets\n",
488 packet_size_bins[size_bin],
489 IEEE80211_RS_RATE(&ni->ni_rates, sd->current_rate[size_bin]),
490 sd->stats[size_bin][sd->current_rate[size_bin]].average_tx_time,
491 sd->stats[size_bin][sd->current_rate[size_bin]].perfect_tx_time,
492 IEEE80211_RS_RATE(&ni->ni_rates, best_ndx),
493 sd->stats[size_bin][best_ndx].average_tx_time,
494 sd->stats[size_bin][best_ndx].perfect_tx_time,
495 sd->packets_since_switch[size_bin]);
497 sd->packets_since_switch[size_bin] = 0;
498 sd->current_rate[size_bin] = best_ndx;
499 sd->ticks_since_switch[size_bin] = ticks;
501 ndx = sd->current_rate[size_bin];
502 sd->packets_since_switch[size_bin]++;
505 * set the visible txrate for this node
506 * to the rate of small packets
513 KASSERT(ndx >= 0 && ndx < ni->ni_rates.rs_nrates, ("ndx is %d", ndx));
515 sd->packets_sent[size_bin]++;
517 cur_ndx = sd->current_rate[size_bin];
518 if (sd->stats[size_bin][cur_ndx].packets_acked == 0)
523 if (rateidx_len > 2) {
524 if ((rc_st->rc_st_flags & IEEE80211_RATECTL_F_RSDESC) == 0 ||
526 rateidx[i++] = cur_ndx;
528 rateidx[i++] = ndx - 1;
530 if (i < rateidx_len && rateidx[i] != 0)
536 sample_update_stats(struct sample_softc *ssc, struct ieee80211_node *ni,
537 int size, int size_bin,
538 const struct ieee80211_ratectl_res res[], int res_len,
539 int rts_tries, int is_fail)
541 struct sample_data *sd = ni->ni_rate_data;
542 int tt, rate, i, ndx, cw = 0, data_tries;
545 ndx = res[0].rc_res_rateidx;
547 rate = IEEE80211_RS_RATE(&ni->ni_rates, ndx);
548 tt = unicast_pkt_time(ssc, ni, rate, size,
549 res[0].rc_res_tries, rts_tries, &cw);
550 data_tries = res[0].rc_res_tries;
552 for (i = 1; i < res_len; ++i) {
553 rate = IEEE80211_RS_RATE(&ni->ni_rates, res[i].rc_res_rateidx);
554 tt += unicast_pkt_time(ssc, ni, rate, size,
555 res[i].rc_res_tries, 0, &cw);
556 data_tries += res[i].rc_res_tries;
559 if (sd->stats[size_bin][ndx].total_packets < (100 / (100 - ssc->smoothing_rate))) {
560 int avg_tx = sd->stats[size_bin][ndx].average_tx_time;
561 int packets = sd->stats[size_bin][ndx].total_packets;
563 /* Average the first few packets. */
564 sd->stats[size_bin][ndx].average_tx_time =
565 (tt + (avg_tx * packets)) / (packets + 1);
568 sd->stats[size_bin][ndx].average_tx_time =
569 ((sd->stats[size_bin][ndx].average_tx_time * ssc->smoothing_rate) +
570 (tt * (100 - ssc->smoothing_rate))) / 100;
576 sd->stats[size_bin][ndx].successive_failures++;
577 for (y = size_bin + 1; y < NUM_PACKET_SIZE_BINS; y++) {
579 * also say larger packets failed since we
580 * assume if a small packet fails at a lower
581 * bit-rate then a larger one will also.
583 sd->stats[y][ndx].successive_failures++;
584 sd->stats[y][ndx].last_tx = ticks;
585 sd->stats[y][ndx].tries += data_tries;
586 sd->stats[y][ndx].total_packets++;
589 sd->stats[size_bin][ndx].packets_acked++;
590 sd->stats[size_bin][ndx].successive_failures = 0;
592 sd->stats[size_bin][ndx].last_tx = ticks;
593 sd->stats[size_bin][ndx].tries += data_tries;
594 sd->stats[size_bin][ndx].total_packets++;
596 if (ndx == sd->current_sample_ndx[size_bin]) {
597 DPRINTF(ssc, 10, "%s: %6D size %d sample rate %d "
598 "tries (d%d/r%d) tt %d avg_tt (%d/%d)%s\n",
599 __func__, ni->ni_macaddr, ":",
600 size, IEEE80211_RS_RATE(&ni->ni_rates, ndx),
601 data_tries, rts_tries, tt,
602 sd->stats[size_bin][ndx].average_tx_time,
603 sd->stats[size_bin][ndx].perfect_tx_time,
604 is_fail ? " fail" : "");
605 sd->sample_tt[size_bin] = tt;
606 sd->current_sample_ndx[size_bin] = -1;
611 sample_tx_complete(void *arg, struct ieee80211_node *ni, int frame_len,
612 const struct ieee80211_ratectl_res res[], int res_len,
613 int data_retry, int rts_retry, int is_fail0)
615 struct sample_softc *ssc = arg;
616 struct sample_data *sd = ni->ni_rate_data;
617 int i, size_bin, size;
619 KKASSERT(frame_len > 0);
620 size_bin = size_to_bin(frame_len);
621 size = bin_to_size(size_bin);
623 if (sd == NULL || !sd->started) {
624 DPRINTF(ssc, 10, "%s: %6D size %d retries (d%d/r%d) "
625 "no rates yet\n", __func__,
627 size, data_retry, rts_retry);
631 for (i = 0; i < res_len; ++i) {
632 if (res[i].rc_res_rateidx >= ni->ni_rates.rs_nrates) {
633 DPRINTF(ssc, 5, "%s: number of rates changed, "
634 "restart\n", __func__);
635 sample_start(ssc, ni);
640 DPRINTF(ssc, 20, "%s: %6D size %d retries (d%d/r%d)\n",
641 __func__, ni->ni_macaddr, ":",
642 size, data_retry, rts_retry);
643 for (i = 0; i < res_len; ++i) {
644 int is_fail = is_fail0;
646 if (i == 0 && (data_retry + 1) > res[0].rc_res_tries &&
647 res[0].rc_res_rateidx == sd->current_sample_ndx[size_bin])
650 sample_update_stats(ssc, ni, size, size_bin,
651 &res[i], res_len - i,
652 rts_retry + 1, is_fail);
657 sample_newassoc(void *arg, struct ieee80211_node *ni, int isnew)
659 struct sample_softc *ssc = arg;
661 DPRINTF(ssc, 5, "%s: %6D isnew %d\n", __func__,
662 ni->ni_macaddr, ":", isnew);
665 sample_start(ssc, ni);
669 * Initialize the tables for a node.
672 sample_start(struct sample_softc *ssc, struct ieee80211_node *ni)
674 #define RATE(_ix) IEEE80211_RS_RATE(&ni->ni_rates, (_ix))
675 struct ieee80211com *ic = ssc->ic;
676 struct sample_data *sd = ni->ni_rate_data;
680 sample_data_alloc(ni);
682 sd = ni->ni_rate_data;
687 sd->static_rate_ndx = -1;
688 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
690 * A fixed rate is to be used; ic_fixed_rate is an
691 * index into the supported rate set. Convert this
692 * to the index into the negotiated rate set for
695 const struct ieee80211_rateset *rs =
696 &ic->ic_sup_rates[ic->ic_curmode];
697 int r = IEEE80211_RS_RATE(rs, ic->ic_fixed_rate);
699 /* NB: the rate set is assumed sorted */
700 srate = ni->ni_rates.rs_nrates - 1;
701 for (; srate >= 0 && RATE(srate) != r; srate--)
704 ("fixed rate %d not in rate set", ic->ic_fixed_rate));
705 sd->static_rate_ndx = srate;
709 DPRINTF(ssc, 1, "%s: %6D size 1600 rate/tt", __func__,
710 ni->ni_macaddr, ":");
711 for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
712 DPRINTF(ssc, 1, " %d/%d", RATE(x),
713 unicast_pkt_time(ssc, ni, RATE(x), 1600, 1, 1, NULL));
715 DPRINTF(ssc, 1, "%s\n", "");
718 /* Set the visible bit-rate to the lowest one available */
721 for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
722 int size = bin_to_size(y);
725 sd->packets_sent[y] = 0;
726 sd->current_sample_ndx[y] = -1;
727 sd->last_sample_ndx[y] = 0;
729 DPRINTF(ssc, 1, "%s: %6D size %d rate/tt", __func__,
730 ni->ni_macaddr, ":", size);
731 for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
732 sd->stats[y][x].successive_failures = 0;
733 sd->stats[y][x].tries = 0;
734 sd->stats[y][x].total_packets = 0;
735 sd->stats[y][x].packets_acked = 0;
736 sd->stats[y][x].last_tx = 0;
738 sd->stats[y][x].perfect_tx_time =
739 unicast_pkt_time(ssc, ni, RATE(x), size,
742 DPRINTF(ssc, 1, " %d/%d", RATE(x),
743 sd->stats[y][x].perfect_tx_time);
745 sd->stats[y][x].average_tx_time =
746 sd->stats[y][x].perfect_tx_time;
748 DPRINTF(ssc, 1, "%s\n", "");
750 /* Set the initial rate */
751 for (ndx = ni->ni_rates.rs_nrates - 1; ndx > 0; ndx--) {
755 sd->current_rate[y] = ndx;
758 DPRINTF(ssc, 1, "%s: %6D %d rates %d%sMbps (%dus)- %d%sMbps (%dus)\n",
759 __func__, ni->ni_macaddr, ":",
760 ni->ni_rates.rs_nrates,
761 RATE(0) / 2, RATE(0) % 2 ? ".5" : "",
762 sd->stats[1][0].perfect_tx_time,
763 RATE(ni->ni_rates.rs_nrates - 1) / 2,
764 RATE(ni->ni_rates.rs_nrates - 1) % 2 ? ".5" : "",
765 sd->stats[1][ni->ni_rates.rs_nrates - 1].perfect_tx_time);
767 if (sd->static_rate_ndx != -1)
768 ni->ni_txrate = sd->static_rate_ndx;
770 ni->ni_txrate = sd->current_rate[0];
777 sample_rate_cb(void *arg, struct ieee80211_node *ni)
779 sample_newassoc(arg, ni, 1);
783 * Reset the rate control state for each 802.11 state transition.
786 sample_newstate(void *arg, enum ieee80211_state state)
788 struct sample_softc *ssc = arg;
790 if (state == IEEE80211_S_RUN) {
791 struct ieee80211com *ic = ssc->ic;
793 if (ic->ic_opmode != IEEE80211_M_STA) {
795 * Sync rates for associated stations and neighbors.
797 ieee80211_iterate_nodes(&ic->ic_sta, sample_rate_cb,
800 sample_newassoc(ssc, ic->ic_bss, 1);
805 sample_sysctl_attach(struct sample_softc *ssc)
807 sysctl_ctx_init(&ssc->sysctl_ctx);
808 ssc->sysctl_oid = SYSCTL_ADD_NODE(&ssc->sysctl_ctx,
809 SYSCTL_CHILDREN(ssc->ic->ic_sysctl_oid),
810 OID_AUTO, "sample_ratectl", CTLFLAG_RD, 0, "");
811 if (ssc->sysctl_oid == NULL) {
812 kprintf("wlan_ratectl_sample: create sysctl tree failed\n");
816 /* XXX bounds check [0..100] */
817 SYSCTL_ADD_INT(&ssc->sysctl_ctx, SYSCTL_CHILDREN(ssc->sysctl_oid),
818 OID_AUTO, "smoothing_rate", CTLFLAG_RW,
819 &ssc->param->sample_smoothing_rate, 0,
821 "retry threshold to credit rate raise (%%)");
823 /* XXX bounds check [2..100] */
824 SYSCTL_ADD_INT(&ssc->sysctl_ctx, SYSCTL_CHILDREN(ssc->sysctl_oid),
825 OID_AUTO, "sample_rate", CTLFLAG_RW,
826 &ssc->param->sample_rate, 0,
828 "# good periods before raising rate");
830 SYSCTL_ADD_INT(&ssc->sysctl_ctx, SYSCTL_CHILDREN(ssc->sysctl_oid),
831 OID_AUTO, "debug", CTLFLAG_RW,
832 &ssc->param->sample_debug, 0,
833 "rate control: debug level");
837 sample_attach(struct ieee80211com *ic)
839 struct sample_softc *ssc;
843 ssc = kmalloc(sizeof(struct sample_softc), M_DEVBUF, M_WAITOK | M_ZERO);
846 ssc->param = ic->ic_ratectl.rc_st_attach(ic, IEEE80211_RATECTL_SAMPLE);
848 sample_sysctl_attach(ssc);
850 sample_newstate(ssc, ic->ic_state);
856 _sample_data_free(void *arg __unused, struct ieee80211_node *ni)
858 sample_data_free(ni);
862 sample_detach(void *arg)
864 struct sample_softc *ssc = arg;
865 struct ieee80211com *ic = ssc->ic;
867 sample_newstate(ssc, IEEE80211_S_INIT);
869 ieee80211_iterate_nodes(&ic->ic_sta, _sample_data_free, NULL);
870 ieee80211_iterate_nodes(&ic->ic_scan, _sample_data_free, NULL);
872 if (ssc->sysctl_oid != NULL)
873 sysctl_ctx_free(&ssc->sysctl_ctx);
874 kfree(ssc, M_DEVBUF);
880 sample_data_alloc(struct ieee80211_node *ni)
882 KKASSERT(ni->ni_rate_data == NULL);
883 ni->ni_rate_data = kmalloc(sizeof(struct sample_data),
884 M_SAMPLE_RATECTL_DATA, M_NOWAIT | M_ZERO);
888 sample_data_free(struct ieee80211_node *ni)
890 if (ni->ni_rate_data != NULL) {
891 kfree(ni->ni_rate_data, M_SAMPLE_RATECTL_DATA);
892 ni->ni_rate_data = NULL;
897 sample_data_dup(const struct ieee80211_node *oni, struct ieee80211_node *nni)
899 if (oni->ni_rate_data == NULL || nni->ni_rate_data == NULL)
902 bcopy(oni->ni_rate_data, nni->ni_rate_data,
903 sizeof(struct sample_data));
910 sample_modevent(module_t mod, int type, void *unused)
914 ieee80211_ratectl_register(&sample);
918 kprintf("wlan_ratectl_sample: still in use "
919 "(%u dynamic refs)\n", sample_nrefs);
922 ieee80211_ratectl_unregister(&sample);
928 static moduledata_t sample_mod = {
929 "wlan_ratectl_sample",
933 DECLARE_MODULE(wlan_ratectl_sample, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
934 MODULE_VERSION(wlan_ratectl_sample, 1);
935 MODULE_DEPEND(wlan_ratectl_sample, wlan, 1, 1, 1);