Home | History | Annotate | Line # | Download | only in net80211
ieee80211_amrr.c revision 1.3.18.4
      1  1.3.18.4   phil /*	$NetBSD: ieee80211_amrr.c,v 1.3.18.4 2018/07/20 20:33:05 phil Exp $ */
      2  1.3.18.2   phil 
      3       1.1  joerg /*	$OpenBSD: ieee80211_amrr.c,v 1.1 2006/06/17 19:07:19 damien Exp $	*/
      4       1.1  joerg 
      5       1.1  joerg /*-
      6  1.3.18.1   phil  * Copyright (c) 2010 Rui Paulo <rpaulo (at) FreeBSD.org>
      7       1.1  joerg  * Copyright (c) 2006
      8       1.1  joerg  *	Damien Bergamini <damien.bergamini (at) free.fr>
      9       1.1  joerg  *
     10       1.1  joerg  * Permission to use, copy, modify, and distribute this software for any
     11       1.1  joerg  * purpose with or without fee is hereby granted, provided that the above
     12       1.1  joerg  * copyright notice and this permission notice appear in all copies.
     13       1.1  joerg  *
     14       1.1  joerg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     15       1.1  joerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     16       1.1  joerg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     17       1.1  joerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     18       1.1  joerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     19       1.1  joerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     20       1.1  joerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     21       1.1  joerg  */
     22       1.1  joerg 
     23       1.2  lukem #include <sys/cdefs.h>
     24  1.3.18.2   phil #ifdef __FreeBSD__
     25  1.3.18.1   phil __FBSDID("$FreeBSD$");
     26  1.3.18.2   phil #endif
     27       1.3  pooka 
     28  1.3.18.1   phil /*-
     29  1.3.18.1   phil  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
     30  1.3.18.1   phil  *
     31  1.3.18.1   phil  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
     32  1.3.18.1   phil  *  Mathieu Lacage, Hossein Manshaei, Thierry Turletti
     33  1.3.18.1   phil  *  INRIA Sophia - Projet Planete
     34  1.3.18.1   phil  *  http://www-sop.inria.fr/rapports/sophia/RR-5208.html
     35  1.3.18.1   phil  */
     36  1.3.18.1   phil #include "opt_wlan.h"
     37       1.2  lukem 
     38       1.1  joerg #include <sys/param.h>
     39       1.1  joerg #include <sys/kernel.h>
     40  1.3.18.1   phil #include <sys/malloc.h>
     41  1.3.18.1   phil #include <sys/module.h>
     42  1.3.18.1   phil #include <sys/sbuf.h>
     43       1.1  joerg #include <sys/socket.h>
     44       1.1  joerg #include <sys/sysctl.h>
     45       1.1  joerg 
     46       1.1  joerg #include <net/if.h>
     47  1.3.18.2   phil #ifdef __FreeBSD__
     48  1.3.18.1   phil #include <net/if_var.h>
     49  1.3.18.2   phil #endif
     50       1.1  joerg #include <net/if_media.h>
     51  1.3.18.2   phil #ifdef __FreeBSD__
     52  1.3.18.1   phil #include <net/ethernet.h>
     53  1.3.18.2   phil #endif
     54  1.3.18.2   phil #ifdef __NetBSD__
     55  1.3.18.2   phil #include <net/route.h>
     56  1.3.18.2   phil #endif
     57       1.1  joerg 
     58       1.1  joerg #ifdef INET
     59       1.1  joerg #include <netinet/in.h>
     60  1.3.18.1   phil #include <netinet/if_ether.h>
     61       1.1  joerg #endif
     62       1.1  joerg 
     63       1.1  joerg #include <net80211/ieee80211_var.h>
     64  1.3.18.1   phil #include <net80211/ieee80211_ht.h>
     65       1.1  joerg #include <net80211/ieee80211_amrr.h>
     66  1.3.18.1   phil #include <net80211/ieee80211_ratectl.h>
     67       1.1  joerg 
     68  1.3.18.2   phil #ifdef __NetBSD__
     69  1.3.18.2   phil #undef  KASSERT
     70  1.3.18.2   phil #define KASSERT(__cond, __complaint) FBSDKASSERT(__cond, __complaint)
     71  1.3.18.2   phil #endif
     72  1.3.18.2   phil 
     73       1.1  joerg #define is_success(amn)	\
     74       1.1  joerg 	((amn)->amn_retrycnt < (amn)->amn_txcnt / 10)
     75       1.1  joerg #define is_failure(amn)	\
     76       1.1  joerg 	((amn)->amn_retrycnt > (amn)->amn_txcnt / 3)
     77       1.1  joerg #define is_enough(amn)		\
     78       1.1  joerg 	((amn)->amn_txcnt > 10)
     79  1.3.18.1   phil 
     80  1.3.18.1   phil static void	amrr_setinterval(const struct ieee80211vap *, int);
     81  1.3.18.1   phil static void	amrr_init(struct ieee80211vap *);
     82  1.3.18.1   phil static void	amrr_deinit(struct ieee80211vap *);
     83  1.3.18.1   phil static void	amrr_node_init(struct ieee80211_node *);
     84  1.3.18.1   phil static void	amrr_node_deinit(struct ieee80211_node *);
     85  1.3.18.1   phil static int	amrr_update(struct ieee80211_amrr *,
     86  1.3.18.1   phil     			struct ieee80211_amrr_node *, struct ieee80211_node *);
     87  1.3.18.1   phil static int	amrr_rate(struct ieee80211_node *, void *, uint32_t);
     88  1.3.18.1   phil static void	amrr_tx_complete(const struct ieee80211_node *,
     89  1.3.18.1   phil 			const struct ieee80211_ratectl_tx_status *);
     90  1.3.18.1   phil static void	amrr_tx_update_cb(void *, struct ieee80211_node *);
     91  1.3.18.1   phil static void	amrr_tx_update(struct ieee80211vap *vap,
     92  1.3.18.1   phil 			struct ieee80211_ratectl_tx_stats *);
     93  1.3.18.4   phil #ifdef notyet
     94  1.3.18.1   phil static void	amrr_sysctlattach(struct ieee80211vap *,
     95  1.3.18.1   phil 			struct sysctl_ctx_list *, struct sysctl_oid *);
     96  1.3.18.4   phil #endif
     97  1.3.18.1   phil static void	amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s);
     98  1.3.18.1   phil 
     99  1.3.18.1   phil /* number of references from net80211 layer */
    100  1.3.18.1   phil static	int nrefs = 0;
    101  1.3.18.1   phil 
    102  1.3.18.3   phil #if __FreeBSD__
    103  1.3.18.1   phil static const struct ieee80211_ratectl amrr = {
    104  1.3.18.2   phil #else
    105  1.3.18.3   phil const struct ieee80211_ratectl ratectl_amrr = {
    106  1.3.18.2   phil #endif
    107  1.3.18.1   phil 	.ir_name	= "amrr",
    108  1.3.18.1   phil 	.ir_attach	= NULL,
    109  1.3.18.1   phil 	.ir_detach	= NULL,
    110  1.3.18.1   phil 	.ir_init	= amrr_init,
    111  1.3.18.1   phil 	.ir_deinit	= amrr_deinit,
    112  1.3.18.1   phil 	.ir_node_init	= amrr_node_init,
    113  1.3.18.1   phil 	.ir_node_deinit	= amrr_node_deinit,
    114  1.3.18.1   phil 	.ir_rate	= amrr_rate,
    115  1.3.18.1   phil 	.ir_tx_complete	= amrr_tx_complete,
    116  1.3.18.1   phil 	.ir_tx_update	= amrr_tx_update,
    117  1.3.18.1   phil 	.ir_setinterval	= amrr_setinterval,
    118  1.3.18.1   phil 	.ir_node_stats	= amrr_node_stats,
    119  1.3.18.1   phil };
    120  1.3.18.3   phil #if __FreeBSD__
    121  1.3.18.1   phil IEEE80211_RATECTL_MODULE(amrr, 1);
    122  1.3.18.1   phil IEEE80211_RATECTL_ALG(amrr, IEEE80211_RATECTL_AMRR, amrr);
    123  1.3.18.2   phil #endif
    124  1.3.18.2   phil 
    125  1.3.18.1   phil static void
    126  1.3.18.1   phil amrr_setinterval(const struct ieee80211vap *vap, int msecs)
    127  1.3.18.1   phil {
    128  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    129  1.3.18.1   phil 	int t;
    130  1.3.18.1   phil 
    131  1.3.18.1   phil 	if (msecs < 100)
    132  1.3.18.1   phil 		msecs = 100;
    133  1.3.18.1   phil 	t = msecs_to_ticks(msecs);
    134  1.3.18.1   phil 	amrr->amrr_interval = (t < 1) ? 1 : t;
    135  1.3.18.1   phil }
    136  1.3.18.1   phil 
    137  1.3.18.1   phil static void
    138  1.3.18.1   phil amrr_init(struct ieee80211vap *vap)
    139  1.3.18.1   phil {
    140  1.3.18.1   phil 	struct ieee80211_amrr *amrr;
    141  1.3.18.1   phil 
    142  1.3.18.1   phil 	KASSERT(vap->iv_rs == NULL, ("%s called multiple times", __func__));
    143  1.3.18.1   phil 
    144  1.3.18.1   phil 	nrefs++;		/* XXX locking */
    145  1.3.18.1   phil 	amrr = vap->iv_rs = IEEE80211_MALLOC(sizeof(struct ieee80211_amrr),
    146  1.3.18.1   phil 	    M_80211_RATECTL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    147  1.3.18.1   phil 	if (amrr == NULL) {
    148  1.3.18.1   phil 		if_printf(vap->iv_ifp, "couldn't alloc ratectl structure\n");
    149  1.3.18.1   phil 		return;
    150  1.3.18.1   phil 	}
    151  1.3.18.1   phil 	amrr->amrr_min_success_threshold = IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD;
    152  1.3.18.1   phil 	amrr->amrr_max_success_threshold = IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD;
    153  1.3.18.1   phil 	amrr_setinterval(vap, 500 /* ms */);
    154  1.3.18.4   phil #ifdef notyet
    155  1.3.18.1   phil 	amrr_sysctlattach(vap, vap->iv_sysctl, vap->iv_oid);
    156  1.3.18.4   phil #endif
    157  1.3.18.1   phil }
    158  1.3.18.1   phil 
    159  1.3.18.1   phil static void
    160  1.3.18.1   phil amrr_deinit(struct ieee80211vap *vap)
    161  1.3.18.1   phil {
    162  1.3.18.1   phil 	IEEE80211_FREE(vap->iv_rs, M_80211_RATECTL);
    163  1.3.18.1   phil 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
    164  1.3.18.1   phil 	nrefs--;		/* XXX locking */
    165  1.3.18.1   phil }
    166  1.3.18.1   phil 
    167  1.3.18.1   phil /*
    168  1.3.18.1   phil  * Return whether 11n rates are possible.
    169  1.3.18.1   phil  *
    170  1.3.18.1   phil  * Some 11n devices may return HT information but no HT rates.
    171  1.3.18.1   phil  * Thus, we shouldn't treat them as an 11n node.
    172  1.3.18.1   phil  */
    173  1.3.18.1   phil static int
    174  1.3.18.1   phil amrr_node_is_11n(struct ieee80211_node *ni)
    175  1.3.18.1   phil {
    176  1.3.18.1   phil 
    177  1.3.18.1   phil 	if (ni->ni_chan == NULL)
    178  1.3.18.1   phil 		return (0);
    179  1.3.18.1   phil 	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
    180  1.3.18.1   phil 		return (0);
    181  1.3.18.1   phil 	if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates == 0)
    182  1.3.18.1   phil 		return (0);
    183  1.3.18.1   phil 	return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
    184  1.3.18.1   phil }
    185  1.3.18.1   phil 
    186  1.3.18.1   phil static void
    187  1.3.18.1   phil amrr_node_init(struct ieee80211_node *ni)
    188       1.1  joerg {
    189  1.3.18.1   phil 	const struct ieee80211_rateset *rs = NULL;
    190  1.3.18.1   phil 	struct ieee80211vap *vap = ni->ni_vap;
    191  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    192  1.3.18.1   phil 	struct ieee80211_amrr_node *amn;
    193  1.3.18.1   phil 	uint8_t rate;
    194  1.3.18.1   phil 
    195  1.3.18.1   phil 	if (ni->ni_rctls == NULL) {
    196  1.3.18.1   phil 		ni->ni_rctls = amn = IEEE80211_MALLOC(sizeof(struct ieee80211_amrr_node),
    197  1.3.18.1   phil 		    M_80211_RATECTL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    198  1.3.18.1   phil 		if (amn == NULL) {
    199  1.3.18.1   phil 			if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
    200  1.3.18.1   phil 			    "structure\n");
    201  1.3.18.1   phil 			return;
    202  1.3.18.1   phil 		}
    203  1.3.18.1   phil 	} else
    204  1.3.18.1   phil 		amn = ni->ni_rctls;
    205  1.3.18.1   phil 	amn->amn_amrr = amrr;
    206       1.1  joerg 	amn->amn_success = 0;
    207       1.1  joerg 	amn->amn_recovery = 0;
    208       1.1  joerg 	amn->amn_txcnt = amn->amn_retrycnt = 0;
    209       1.1  joerg 	amn->amn_success_threshold = amrr->amrr_min_success_threshold;
    210  1.3.18.1   phil 
    211  1.3.18.1   phil 	/* 11n or not? Pick the right rateset */
    212  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    213  1.3.18.1   phil 		/* XXX ew */
    214  1.3.18.1   phil 		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    215  1.3.18.1   phil 		    "%s: 11n node", __func__);
    216  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    217  1.3.18.1   phil 	} else {
    218  1.3.18.1   phil 		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    219  1.3.18.1   phil 		    "%s: non-11n node", __func__);
    220  1.3.18.1   phil 		rs = &ni->ni_rates;
    221  1.3.18.1   phil 	}
    222  1.3.18.1   phil 
    223  1.3.18.1   phil 	/* Initial rate - lowest */
    224  1.3.18.1   phil 	rate = rs->rs_rates[0];
    225  1.3.18.1   phil 
    226  1.3.18.1   phil 	/* XXX clear the basic rate flag if it's not 11n */
    227  1.3.18.1   phil 	if (! amrr_node_is_11n(ni))
    228  1.3.18.1   phil 		rate &= IEEE80211_RATE_VAL;
    229  1.3.18.1   phil 
    230  1.3.18.1   phil 	/* pick initial rate from the rateset - HT or otherwise */
    231  1.3.18.1   phil 	/* Pick something low that's likely to succeed */
    232  1.3.18.1   phil 	for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0;
    233  1.3.18.1   phil 	    amn->amn_rix--) {
    234  1.3.18.1   phil 		/* legacy - anything < 36mbit, stop searching */
    235  1.3.18.1   phil 		/* 11n - stop at MCS4 */
    236  1.3.18.1   phil 		if (amrr_node_is_11n(ni)) {
    237  1.3.18.1   phil 			if ((rs->rs_rates[amn->amn_rix] & 0x1f) < 4)
    238  1.3.18.1   phil 				break;
    239  1.3.18.1   phil 		} else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72)
    240  1.3.18.1   phil 			break;
    241  1.3.18.1   phil 	}
    242  1.3.18.1   phil 	rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
    243  1.3.18.1   phil 
    244  1.3.18.1   phil 	/* if the rate is an 11n rate, ensure the MCS bit is set */
    245  1.3.18.1   phil 	if (amrr_node_is_11n(ni))
    246  1.3.18.1   phil 		rate |= IEEE80211_RATE_MCS;
    247  1.3.18.1   phil 
    248  1.3.18.1   phil 	/* Assign initial rate from the rateset */
    249  1.3.18.1   phil 	ni->ni_txrate = rate;
    250  1.3.18.1   phil 	amn->amn_ticks = ticks;
    251  1.3.18.1   phil 
    252  1.3.18.1   phil 	/* XXX TODO: we really need a rate-to-string method */
    253  1.3.18.1   phil 	/* XXX TODO: non-11n rate should be divided by two.. */
    254  1.3.18.1   phil 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    255  1.3.18.1   phil 	    "AMRR: nrates=%d, initial rate %s%d",
    256  1.3.18.1   phil 	    rs->rs_nrates,
    257  1.3.18.1   phil 	    amrr_node_is_11n(ni) ? "MCS " : "",
    258  1.3.18.1   phil 	    rate & IEEE80211_RATE_VAL);
    259       1.1  joerg }
    260       1.1  joerg 
    261  1.3.18.1   phil static void
    262  1.3.18.1   phil amrr_node_deinit(struct ieee80211_node *ni)
    263       1.1  joerg {
    264  1.3.18.1   phil 	IEEE80211_FREE(ni->ni_rctls, M_80211_RATECTL);
    265  1.3.18.1   phil }
    266  1.3.18.1   phil 
    267  1.3.18.1   phil static int
    268  1.3.18.1   phil amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
    269  1.3.18.1   phil     struct ieee80211_node *ni)
    270  1.3.18.1   phil {
    271  1.3.18.1   phil 	int rix = amn->amn_rix;
    272  1.3.18.1   phil 	const struct ieee80211_rateset *rs = NULL;
    273  1.3.18.1   phil 
    274  1.3.18.1   phil 	KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));
    275  1.3.18.1   phil 
    276  1.3.18.1   phil 	/* 11n or not? Pick the right rateset */
    277  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    278  1.3.18.1   phil 		/* XXX ew */
    279  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    280  1.3.18.1   phil 	} else {
    281  1.3.18.1   phil 		rs = &ni->ni_rates;
    282  1.3.18.1   phil 	}
    283       1.1  joerg 
    284  1.3.18.1   phil 	/* XXX TODO: we really need a rate-to-string method */
    285  1.3.18.1   phil 	/* XXX TODO: non-11n rate should be divided by two.. */
    286  1.3.18.1   phil 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    287  1.3.18.1   phil 	    "AMRR: current rate %d, txcnt=%d, retrycnt=%d",
    288  1.3.18.1   phil 	    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
    289  1.3.18.1   phil 	    amn->amn_txcnt,
    290  1.3.18.1   phil 	    amn->amn_retrycnt);
    291  1.3.18.1   phil 
    292  1.3.18.1   phil 	/*
    293  1.3.18.1   phil 	 * XXX This is totally bogus for 11n, as although high MCS
    294  1.3.18.1   phil 	 * rates for each stream may be failing, the next stream
    295  1.3.18.1   phil 	 * should be checked.
    296  1.3.18.1   phil 	 *
    297  1.3.18.1   phil 	 * Eg, if MCS5 is ok but MCS6/7 isn't, and we can go up to
    298  1.3.18.1   phil 	 * MCS23, we should skip 6/7 and try 8 onwards.
    299  1.3.18.1   phil 	 */
    300  1.3.18.1   phil 	if (is_success(amn)) {
    301       1.1  joerg 		amn->amn_success++;
    302       1.1  joerg 		if (amn->amn_success >= amn->amn_success_threshold &&
    303  1.3.18.1   phil 		    rix + 1 < rs->rs_nrates) {
    304       1.1  joerg 			amn->amn_recovery = 1;
    305       1.1  joerg 			amn->amn_success = 0;
    306  1.3.18.1   phil 			rix++;
    307  1.3.18.1   phil 			/* XXX TODO: we really need a rate-to-string method */
    308  1.3.18.1   phil 			/* XXX TODO: non-11n rate should be divided by two.. */
    309  1.3.18.1   phil 			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    310  1.3.18.1   phil 			    "AMRR increasing rate %d (txcnt=%d retrycnt=%d)",
    311  1.3.18.1   phil 			    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
    312       1.1  joerg 			    amn->amn_txcnt, amn->amn_retrycnt);
    313       1.1  joerg 		} else {
    314       1.1  joerg 			amn->amn_recovery = 0;
    315       1.1  joerg 		}
    316       1.1  joerg 	} else if (is_failure(amn)) {
    317       1.1  joerg 		amn->amn_success = 0;
    318  1.3.18.1   phil 		if (rix > 0) {
    319       1.1  joerg 			if (amn->amn_recovery) {
    320       1.1  joerg 				amn->amn_success_threshold *= 2;
    321       1.1  joerg 				if (amn->amn_success_threshold >
    322       1.1  joerg 				    amrr->amrr_max_success_threshold)
    323       1.1  joerg 					amn->amn_success_threshold =
    324       1.1  joerg 					    amrr->amrr_max_success_threshold;
    325       1.1  joerg 			} else {
    326       1.1  joerg 				amn->amn_success_threshold =
    327       1.1  joerg 				    amrr->amrr_min_success_threshold;
    328       1.1  joerg 			}
    329  1.3.18.1   phil 			rix--;
    330  1.3.18.1   phil 			/* XXX TODO: we really need a rate-to-string method */
    331  1.3.18.1   phil 			/* XXX TODO: non-11n rate should be divided by two.. */
    332  1.3.18.1   phil 			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    333  1.3.18.1   phil 			    "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)",
    334  1.3.18.1   phil 			    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
    335       1.1  joerg 			    amn->amn_txcnt, amn->amn_retrycnt);
    336       1.1  joerg 		}
    337       1.1  joerg 		amn->amn_recovery = 0;
    338       1.1  joerg 	}
    339       1.1  joerg 
    340  1.3.18.1   phil 	/* reset counters */
    341  1.3.18.1   phil 	amn->amn_txcnt = 0;
    342  1.3.18.1   phil 	amn->amn_retrycnt = 0;
    343  1.3.18.1   phil 
    344  1.3.18.1   phil 	return rix;
    345  1.3.18.1   phil }
    346  1.3.18.1   phil 
    347  1.3.18.1   phil /*
    348  1.3.18.1   phil  * Return the rate index to use in sending a data frame.
    349  1.3.18.1   phil  * Update our internal state if it's been long enough.
    350  1.3.18.1   phil  * If the rate changes we also update ni_txrate to match.
    351  1.3.18.1   phil  */
    352  1.3.18.1   phil static int
    353  1.3.18.1   phil amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
    354  1.3.18.1   phil {
    355  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    356  1.3.18.1   phil 	struct ieee80211_amrr *amrr = amn->amn_amrr;
    357  1.3.18.1   phil 	const struct ieee80211_rateset *rs = NULL;
    358  1.3.18.1   phil 	int rix;
    359  1.3.18.1   phil 
    360  1.3.18.1   phil 	/* 11n or not? Pick the right rateset */
    361  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    362  1.3.18.1   phil 		/* XXX ew */
    363  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    364  1.3.18.1   phil 	} else {
    365  1.3.18.1   phil 		rs = &ni->ni_rates;
    366  1.3.18.1   phil 	}
    367  1.3.18.1   phil 
    368  1.3.18.1   phil 	if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) {
    369  1.3.18.1   phil 		rix = amrr_update(amrr, amn, ni);
    370  1.3.18.1   phil 		if (rix != amn->amn_rix) {
    371  1.3.18.1   phil 			/* update public rate */
    372  1.3.18.1   phil 			ni->ni_txrate = rs->rs_rates[rix];
    373  1.3.18.1   phil 			/* XXX strip basic rate flag from txrate, if non-11n */
    374  1.3.18.1   phil 			if (amrr_node_is_11n(ni))
    375  1.3.18.1   phil 				ni->ni_txrate |= IEEE80211_RATE_MCS;
    376  1.3.18.1   phil 			else
    377  1.3.18.1   phil 				ni->ni_txrate &= IEEE80211_RATE_VAL;
    378  1.3.18.1   phil 			amn->amn_rix = rix;
    379  1.3.18.1   phil 		}
    380  1.3.18.1   phil 		amn->amn_ticks = ticks;
    381  1.3.18.1   phil 	} else
    382  1.3.18.1   phil 		rix = amn->amn_rix;
    383  1.3.18.1   phil 	return rix;
    384  1.3.18.1   phil }
    385  1.3.18.1   phil 
    386  1.3.18.1   phil /*
    387  1.3.18.1   phil  * Update statistics with tx complete status.  Ok is non-zero
    388  1.3.18.1   phil  * if the packet is known to be ACK'd.  Retries has the number
    389  1.3.18.1   phil  * retransmissions (i.e. xmit attempts - 1).
    390  1.3.18.1   phil  */
    391  1.3.18.1   phil static void
    392  1.3.18.1   phil amrr_tx_complete(const struct ieee80211_node *ni,
    393  1.3.18.1   phil     const struct ieee80211_ratectl_tx_status *status)
    394  1.3.18.1   phil {
    395  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    396  1.3.18.1   phil 	int retries;
    397  1.3.18.1   phil 
    398  1.3.18.1   phil 	retries = 0;
    399  1.3.18.1   phil 	if (status->flags & IEEE80211_RATECTL_STATUS_LONG_RETRY)
    400  1.3.18.1   phil 		retries = status->long_retries;
    401  1.3.18.1   phil 
    402  1.3.18.1   phil 	amn->amn_txcnt++;
    403  1.3.18.1   phil 	if (status->status == IEEE80211_RATECTL_TX_SUCCESS)
    404  1.3.18.1   phil 		amn->amn_success++;
    405  1.3.18.1   phil 	amn->amn_retrycnt += retries;
    406  1.3.18.1   phil }
    407  1.3.18.1   phil 
    408  1.3.18.1   phil static void
    409  1.3.18.1   phil amrr_tx_update_cb(void *arg, struct ieee80211_node *ni)
    410  1.3.18.1   phil {
    411  1.3.18.1   phil 	struct ieee80211_ratectl_tx_stats *stats = arg;
    412  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    413  1.3.18.1   phil 	int txcnt, success, retrycnt;
    414  1.3.18.1   phil 
    415  1.3.18.1   phil 	txcnt = stats->nframes;
    416  1.3.18.1   phil 	success = stats->nsuccess;
    417  1.3.18.1   phil 	retrycnt = 0;
    418  1.3.18.1   phil 	if (stats->flags & IEEE80211_RATECTL_TX_STATS_RETRIES)
    419  1.3.18.1   phil 		retrycnt = stats->nretries;
    420  1.3.18.1   phil 
    421  1.3.18.1   phil 	amn->amn_txcnt += txcnt;
    422  1.3.18.1   phil 	amn->amn_success += success;
    423  1.3.18.1   phil 	amn->amn_retrycnt += retrycnt;
    424  1.3.18.1   phil }
    425  1.3.18.1   phil 
    426  1.3.18.1   phil /*
    427  1.3.18.1   phil  * Set tx count/retry statistics explicitly.  Intended for
    428  1.3.18.1   phil  * drivers that poll the device for statistics maintained
    429  1.3.18.1   phil  * in the device.
    430  1.3.18.1   phil  */
    431  1.3.18.1   phil static void
    432  1.3.18.1   phil amrr_tx_update(struct ieee80211vap *vap,
    433  1.3.18.1   phil     struct ieee80211_ratectl_tx_stats *stats)
    434  1.3.18.1   phil {
    435  1.3.18.1   phil 
    436  1.3.18.1   phil 	if (stats->flags & IEEE80211_RATECTL_TX_STATS_NODE)
    437  1.3.18.1   phil 		amrr_tx_update_cb(stats, stats->ni);
    438  1.3.18.1   phil 	else {
    439  1.3.18.1   phil 		ieee80211_iterate_nodes_vap(&vap->iv_ic->ic_sta, vap,
    440  1.3.18.1   phil 		    amrr_tx_update_cb, stats);
    441  1.3.18.1   phil 	}
    442  1.3.18.1   phil }
    443  1.3.18.1   phil 
    444  1.3.18.2   phil #ifdef notyet
    445  1.3.18.1   phil static int
    446  1.3.18.1   phil amrr_sysctl_interval(SYSCTL_HANDLER_ARGS)
    447  1.3.18.1   phil {
    448  1.3.18.1   phil 	struct ieee80211vap *vap = arg1;
    449  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    450  1.3.18.1   phil 	int msecs = ticks_to_msecs(amrr->amrr_interval);
    451  1.3.18.1   phil 	int error;
    452  1.3.18.1   phil 
    453  1.3.18.1   phil 	error = sysctl_handle_int(oidp, &msecs, 0, req);
    454  1.3.18.1   phil 	if (error || !req->newptr)
    455  1.3.18.1   phil 		return error;
    456  1.3.18.1   phil 	amrr_setinterval(vap, msecs);
    457  1.3.18.1   phil 	return 0;
    458  1.3.18.1   phil }
    459  1.3.18.2   phil #endif
    460  1.3.18.1   phil 
    461  1.3.18.4   phil #ifdef notyet
    462  1.3.18.1   phil static void
    463  1.3.18.1   phil amrr_sysctlattach(struct ieee80211vap *vap,
    464  1.3.18.1   phil     struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
    465  1.3.18.1   phil {
    466  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    467  1.3.18.1   phil 
    468  1.3.18.1   phil 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
    469  1.3.18.1   phil 	    "amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap,
    470  1.3.18.1   phil 	    0, amrr_sysctl_interval, "I", "amrr operation interval (ms)");
    471  1.3.18.1   phil 	/* XXX bounds check values */
    472  1.3.18.1   phil 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
    473  1.3.18.1   phil 	    "amrr_max_sucess_threshold", CTLFLAG_RW,
    474  1.3.18.1   phil 	    &amrr->amrr_max_success_threshold, 0, "");
    475  1.3.18.1   phil 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
    476  1.3.18.1   phil 	    "amrr_min_sucess_threshold", CTLFLAG_RW,
    477  1.3.18.1   phil 	    &amrr->amrr_min_success_threshold, 0, "");
    478  1.3.18.1   phil }
    479  1.3.18.4   phil #endif
    480  1.3.18.1   phil 
    481  1.3.18.1   phil static void
    482  1.3.18.1   phil amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s)
    483  1.3.18.1   phil {
    484  1.3.18.1   phil 	int rate;
    485  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    486  1.3.18.1   phil 	struct ieee80211_rateset *rs;
    487  1.3.18.1   phil 
    488  1.3.18.1   phil 	/* XXX TODO: check locking? */
    489  1.3.18.1   phil 
    490  1.3.18.1   phil 	/* XXX TODO: this should be a method */
    491  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    492  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    493  1.3.18.1   phil 		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
    494  1.3.18.1   phil 		sbuf_printf(s, "rate: MCS %d\n", rate);
    495  1.3.18.1   phil 	} else {
    496  1.3.18.1   phil 		rs = &ni->ni_rates;
    497  1.3.18.1   phil 		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
    498  1.3.18.1   phil 		sbuf_printf(s, "rate: %d Mbit\n", rate / 2);
    499  1.3.18.1   phil 	}
    500  1.3.18.1   phil 
    501  1.3.18.1   phil 	sbuf_printf(s, "ticks: %d\n", amn->amn_ticks);
    502  1.3.18.1   phil 	sbuf_printf(s, "txcnt: %u\n", amn->amn_txcnt);
    503  1.3.18.1   phil 	sbuf_printf(s, "success: %u\n", amn->amn_success);
    504  1.3.18.1   phil 	sbuf_printf(s, "success_threshold: %u\n", amn->amn_success_threshold);
    505  1.3.18.1   phil 	sbuf_printf(s, "recovery: %u\n", amn->amn_recovery);
    506  1.3.18.1   phil 	sbuf_printf(s, "retry_cnt: %u\n", amn->amn_retrycnt);
    507       1.1  joerg }
    508  1.3.18.2   phil 
    509