Home | History | Annotate | Line # | Download | only in net80211
ieee80211_amrr.c revision 1.3.18.2
      1  1.3.18.2   phil /*	$NetBSD: ieee80211_amrr.c,v 1.3.18.2 2018/07/12 16:35:34 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.1   phil static void	amrr_sysctlattach(struct ieee80211vap *,
     94  1.3.18.1   phil 			struct sysctl_ctx_list *, struct sysctl_oid *);
     95  1.3.18.1   phil static void	amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s);
     96  1.3.18.1   phil 
     97  1.3.18.1   phil /* number of references from net80211 layer */
     98  1.3.18.1   phil static	int nrefs = 0;
     99  1.3.18.1   phil 
    100  1.3.18.2   phil #ifdef notyet
    101  1.3.18.1   phil static const struct ieee80211_ratectl amrr = {
    102  1.3.18.2   phil #else
    103  1.3.18.2   phil static const struct ieee80211_ratectl __unused amrr = {
    104  1.3.18.2   phil #endif
    105  1.3.18.1   phil 	.ir_name	= "amrr",
    106  1.3.18.1   phil 	.ir_attach	= NULL,
    107  1.3.18.1   phil 	.ir_detach	= NULL,
    108  1.3.18.1   phil 	.ir_init	= amrr_init,
    109  1.3.18.1   phil 	.ir_deinit	= amrr_deinit,
    110  1.3.18.1   phil 	.ir_node_init	= amrr_node_init,
    111  1.3.18.1   phil 	.ir_node_deinit	= amrr_node_deinit,
    112  1.3.18.1   phil 	.ir_rate	= amrr_rate,
    113  1.3.18.1   phil 	.ir_tx_complete	= amrr_tx_complete,
    114  1.3.18.1   phil 	.ir_tx_update	= amrr_tx_update,
    115  1.3.18.1   phil 	.ir_setinterval	= amrr_setinterval,
    116  1.3.18.1   phil 	.ir_node_stats	= amrr_node_stats,
    117  1.3.18.1   phil };
    118  1.3.18.1   phil IEEE80211_RATECTL_MODULE(amrr, 1);
    119  1.3.18.1   phil IEEE80211_RATECTL_ALG(amrr, IEEE80211_RATECTL_AMRR, amrr);
    120  1.3.18.1   phil 
    121  1.3.18.2   phil #ifdef __NetBSD__
    122  1.3.18.2   phil #define amrr amrr0
    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.1   phil 	amrr_sysctlattach(vap, vap->iv_sysctl, vap->iv_oid);
    155  1.3.18.1   phil }
    156  1.3.18.1   phil 
    157  1.3.18.1   phil static void
    158  1.3.18.1   phil amrr_deinit(struct ieee80211vap *vap)
    159  1.3.18.1   phil {
    160  1.3.18.1   phil 	IEEE80211_FREE(vap->iv_rs, M_80211_RATECTL);
    161  1.3.18.1   phil 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
    162  1.3.18.1   phil 	nrefs--;		/* XXX locking */
    163  1.3.18.1   phil }
    164  1.3.18.1   phil 
    165  1.3.18.1   phil /*
    166  1.3.18.1   phil  * Return whether 11n rates are possible.
    167  1.3.18.1   phil  *
    168  1.3.18.1   phil  * Some 11n devices may return HT information but no HT rates.
    169  1.3.18.1   phil  * Thus, we shouldn't treat them as an 11n node.
    170  1.3.18.1   phil  */
    171  1.3.18.1   phil static int
    172  1.3.18.1   phil amrr_node_is_11n(struct ieee80211_node *ni)
    173  1.3.18.1   phil {
    174  1.3.18.1   phil 
    175  1.3.18.1   phil 	if (ni->ni_chan == NULL)
    176  1.3.18.1   phil 		return (0);
    177  1.3.18.1   phil 	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
    178  1.3.18.1   phil 		return (0);
    179  1.3.18.1   phil 	if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates == 0)
    180  1.3.18.1   phil 		return (0);
    181  1.3.18.1   phil 	return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
    182  1.3.18.1   phil }
    183  1.3.18.1   phil 
    184  1.3.18.1   phil static void
    185  1.3.18.1   phil amrr_node_init(struct ieee80211_node *ni)
    186       1.1  joerg {
    187  1.3.18.1   phil 	const struct ieee80211_rateset *rs = NULL;
    188  1.3.18.1   phil 	struct ieee80211vap *vap = ni->ni_vap;
    189  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    190  1.3.18.1   phil 	struct ieee80211_amrr_node *amn;
    191  1.3.18.1   phil 	uint8_t rate;
    192  1.3.18.1   phil 
    193  1.3.18.1   phil 	if (ni->ni_rctls == NULL) {
    194  1.3.18.1   phil 		ni->ni_rctls = amn = IEEE80211_MALLOC(sizeof(struct ieee80211_amrr_node),
    195  1.3.18.1   phil 		    M_80211_RATECTL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    196  1.3.18.1   phil 		if (amn == NULL) {
    197  1.3.18.1   phil 			if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
    198  1.3.18.1   phil 			    "structure\n");
    199  1.3.18.1   phil 			return;
    200  1.3.18.1   phil 		}
    201  1.3.18.1   phil 	} else
    202  1.3.18.1   phil 		amn = ni->ni_rctls;
    203  1.3.18.1   phil 	amn->amn_amrr = amrr;
    204       1.1  joerg 	amn->amn_success = 0;
    205       1.1  joerg 	amn->amn_recovery = 0;
    206       1.1  joerg 	amn->amn_txcnt = amn->amn_retrycnt = 0;
    207       1.1  joerg 	amn->amn_success_threshold = amrr->amrr_min_success_threshold;
    208  1.3.18.1   phil 
    209  1.3.18.1   phil 	/* 11n or not? Pick the right rateset */
    210  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    211  1.3.18.1   phil 		/* XXX ew */
    212  1.3.18.1   phil 		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    213  1.3.18.1   phil 		    "%s: 11n node", __func__);
    214  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    215  1.3.18.1   phil 	} else {
    216  1.3.18.1   phil 		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    217  1.3.18.1   phil 		    "%s: non-11n node", __func__);
    218  1.3.18.1   phil 		rs = &ni->ni_rates;
    219  1.3.18.1   phil 	}
    220  1.3.18.1   phil 
    221  1.3.18.1   phil 	/* Initial rate - lowest */
    222  1.3.18.1   phil 	rate = rs->rs_rates[0];
    223  1.3.18.1   phil 
    224  1.3.18.1   phil 	/* XXX clear the basic rate flag if it's not 11n */
    225  1.3.18.1   phil 	if (! amrr_node_is_11n(ni))
    226  1.3.18.1   phil 		rate &= IEEE80211_RATE_VAL;
    227  1.3.18.1   phil 
    228  1.3.18.1   phil 	/* pick initial rate from the rateset - HT or otherwise */
    229  1.3.18.1   phil 	/* Pick something low that's likely to succeed */
    230  1.3.18.1   phil 	for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0;
    231  1.3.18.1   phil 	    amn->amn_rix--) {
    232  1.3.18.1   phil 		/* legacy - anything < 36mbit, stop searching */
    233  1.3.18.1   phil 		/* 11n - stop at MCS4 */
    234  1.3.18.1   phil 		if (amrr_node_is_11n(ni)) {
    235  1.3.18.1   phil 			if ((rs->rs_rates[amn->amn_rix] & 0x1f) < 4)
    236  1.3.18.1   phil 				break;
    237  1.3.18.1   phil 		} else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72)
    238  1.3.18.1   phil 			break;
    239  1.3.18.1   phil 	}
    240  1.3.18.1   phil 	rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
    241  1.3.18.1   phil 
    242  1.3.18.1   phil 	/* if the rate is an 11n rate, ensure the MCS bit is set */
    243  1.3.18.1   phil 	if (amrr_node_is_11n(ni))
    244  1.3.18.1   phil 		rate |= IEEE80211_RATE_MCS;
    245  1.3.18.1   phil 
    246  1.3.18.1   phil 	/* Assign initial rate from the rateset */
    247  1.3.18.1   phil 	ni->ni_txrate = rate;
    248  1.3.18.1   phil 	amn->amn_ticks = ticks;
    249  1.3.18.1   phil 
    250  1.3.18.1   phil 	/* XXX TODO: we really need a rate-to-string method */
    251  1.3.18.1   phil 	/* XXX TODO: non-11n rate should be divided by two.. */
    252  1.3.18.1   phil 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    253  1.3.18.1   phil 	    "AMRR: nrates=%d, initial rate %s%d",
    254  1.3.18.1   phil 	    rs->rs_nrates,
    255  1.3.18.1   phil 	    amrr_node_is_11n(ni) ? "MCS " : "",
    256  1.3.18.1   phil 	    rate & IEEE80211_RATE_VAL);
    257       1.1  joerg }
    258       1.1  joerg 
    259  1.3.18.1   phil static void
    260  1.3.18.1   phil amrr_node_deinit(struct ieee80211_node *ni)
    261       1.1  joerg {
    262  1.3.18.1   phil 	IEEE80211_FREE(ni->ni_rctls, M_80211_RATECTL);
    263  1.3.18.1   phil }
    264  1.3.18.1   phil 
    265  1.3.18.1   phil static int
    266  1.3.18.1   phil amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
    267  1.3.18.1   phil     struct ieee80211_node *ni)
    268  1.3.18.1   phil {
    269  1.3.18.1   phil 	int rix = amn->amn_rix;
    270  1.3.18.1   phil 	const struct ieee80211_rateset *rs = NULL;
    271  1.3.18.1   phil 
    272  1.3.18.1   phil 	KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));
    273  1.3.18.1   phil 
    274  1.3.18.1   phil 	/* 11n or not? Pick the right rateset */
    275  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    276  1.3.18.1   phil 		/* XXX ew */
    277  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    278  1.3.18.1   phil 	} else {
    279  1.3.18.1   phil 		rs = &ni->ni_rates;
    280  1.3.18.1   phil 	}
    281       1.1  joerg 
    282  1.3.18.1   phil 	/* XXX TODO: we really need a rate-to-string method */
    283  1.3.18.1   phil 	/* XXX TODO: non-11n rate should be divided by two.. */
    284  1.3.18.1   phil 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    285  1.3.18.1   phil 	    "AMRR: current rate %d, txcnt=%d, retrycnt=%d",
    286  1.3.18.1   phil 	    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
    287  1.3.18.1   phil 	    amn->amn_txcnt,
    288  1.3.18.1   phil 	    amn->amn_retrycnt);
    289  1.3.18.1   phil 
    290  1.3.18.1   phil 	/*
    291  1.3.18.1   phil 	 * XXX This is totally bogus for 11n, as although high MCS
    292  1.3.18.1   phil 	 * rates for each stream may be failing, the next stream
    293  1.3.18.1   phil 	 * should be checked.
    294  1.3.18.1   phil 	 *
    295  1.3.18.1   phil 	 * Eg, if MCS5 is ok but MCS6/7 isn't, and we can go up to
    296  1.3.18.1   phil 	 * MCS23, we should skip 6/7 and try 8 onwards.
    297  1.3.18.1   phil 	 */
    298  1.3.18.1   phil 	if (is_success(amn)) {
    299       1.1  joerg 		amn->amn_success++;
    300       1.1  joerg 		if (amn->amn_success >= amn->amn_success_threshold &&
    301  1.3.18.1   phil 		    rix + 1 < rs->rs_nrates) {
    302       1.1  joerg 			amn->amn_recovery = 1;
    303       1.1  joerg 			amn->amn_success = 0;
    304  1.3.18.1   phil 			rix++;
    305  1.3.18.1   phil 			/* XXX TODO: we really need a rate-to-string method */
    306  1.3.18.1   phil 			/* XXX TODO: non-11n rate should be divided by two.. */
    307  1.3.18.1   phil 			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    308  1.3.18.1   phil 			    "AMRR increasing rate %d (txcnt=%d retrycnt=%d)",
    309  1.3.18.1   phil 			    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
    310       1.1  joerg 			    amn->amn_txcnt, amn->amn_retrycnt);
    311       1.1  joerg 		} else {
    312       1.1  joerg 			amn->amn_recovery = 0;
    313       1.1  joerg 		}
    314       1.1  joerg 	} else if (is_failure(amn)) {
    315       1.1  joerg 		amn->amn_success = 0;
    316  1.3.18.1   phil 		if (rix > 0) {
    317       1.1  joerg 			if (amn->amn_recovery) {
    318       1.1  joerg 				amn->amn_success_threshold *= 2;
    319       1.1  joerg 				if (amn->amn_success_threshold >
    320       1.1  joerg 				    amrr->amrr_max_success_threshold)
    321       1.1  joerg 					amn->amn_success_threshold =
    322       1.1  joerg 					    amrr->amrr_max_success_threshold;
    323       1.1  joerg 			} else {
    324       1.1  joerg 				amn->amn_success_threshold =
    325       1.1  joerg 				    amrr->amrr_min_success_threshold;
    326       1.1  joerg 			}
    327  1.3.18.1   phil 			rix--;
    328  1.3.18.1   phil 			/* XXX TODO: we really need a rate-to-string method */
    329  1.3.18.1   phil 			/* XXX TODO: non-11n rate should be divided by two.. */
    330  1.3.18.1   phil 			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
    331  1.3.18.1   phil 			    "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)",
    332  1.3.18.1   phil 			    rs->rs_rates[rix] & IEEE80211_RATE_VAL,
    333       1.1  joerg 			    amn->amn_txcnt, amn->amn_retrycnt);
    334       1.1  joerg 		}
    335       1.1  joerg 		amn->amn_recovery = 0;
    336       1.1  joerg 	}
    337       1.1  joerg 
    338  1.3.18.1   phil 	/* reset counters */
    339  1.3.18.1   phil 	amn->amn_txcnt = 0;
    340  1.3.18.1   phil 	amn->amn_retrycnt = 0;
    341  1.3.18.1   phil 
    342  1.3.18.1   phil 	return rix;
    343  1.3.18.1   phil }
    344  1.3.18.1   phil 
    345  1.3.18.1   phil /*
    346  1.3.18.1   phil  * Return the rate index to use in sending a data frame.
    347  1.3.18.1   phil  * Update our internal state if it's been long enough.
    348  1.3.18.1   phil  * If the rate changes we also update ni_txrate to match.
    349  1.3.18.1   phil  */
    350  1.3.18.1   phil static int
    351  1.3.18.1   phil amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
    352  1.3.18.1   phil {
    353  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    354  1.3.18.1   phil 	struct ieee80211_amrr *amrr = amn->amn_amrr;
    355  1.3.18.1   phil 	const struct ieee80211_rateset *rs = NULL;
    356  1.3.18.1   phil 	int rix;
    357  1.3.18.1   phil 
    358  1.3.18.1   phil 	/* 11n or not? Pick the right rateset */
    359  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    360  1.3.18.1   phil 		/* XXX ew */
    361  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    362  1.3.18.1   phil 	} else {
    363  1.3.18.1   phil 		rs = &ni->ni_rates;
    364  1.3.18.1   phil 	}
    365  1.3.18.1   phil 
    366  1.3.18.1   phil 	if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) {
    367  1.3.18.1   phil 		rix = amrr_update(amrr, amn, ni);
    368  1.3.18.1   phil 		if (rix != amn->amn_rix) {
    369  1.3.18.1   phil 			/* update public rate */
    370  1.3.18.1   phil 			ni->ni_txrate = rs->rs_rates[rix];
    371  1.3.18.1   phil 			/* XXX strip basic rate flag from txrate, if non-11n */
    372  1.3.18.1   phil 			if (amrr_node_is_11n(ni))
    373  1.3.18.1   phil 				ni->ni_txrate |= IEEE80211_RATE_MCS;
    374  1.3.18.1   phil 			else
    375  1.3.18.1   phil 				ni->ni_txrate &= IEEE80211_RATE_VAL;
    376  1.3.18.1   phil 			amn->amn_rix = rix;
    377  1.3.18.1   phil 		}
    378  1.3.18.1   phil 		amn->amn_ticks = ticks;
    379  1.3.18.1   phil 	} else
    380  1.3.18.1   phil 		rix = amn->amn_rix;
    381  1.3.18.1   phil 	return rix;
    382  1.3.18.1   phil }
    383  1.3.18.1   phil 
    384  1.3.18.1   phil /*
    385  1.3.18.1   phil  * Update statistics with tx complete status.  Ok is non-zero
    386  1.3.18.1   phil  * if the packet is known to be ACK'd.  Retries has the number
    387  1.3.18.1   phil  * retransmissions (i.e. xmit attempts - 1).
    388  1.3.18.1   phil  */
    389  1.3.18.1   phil static void
    390  1.3.18.1   phil amrr_tx_complete(const struct ieee80211_node *ni,
    391  1.3.18.1   phil     const struct ieee80211_ratectl_tx_status *status)
    392  1.3.18.1   phil {
    393  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    394  1.3.18.1   phil 	int retries;
    395  1.3.18.1   phil 
    396  1.3.18.1   phil 	retries = 0;
    397  1.3.18.1   phil 	if (status->flags & IEEE80211_RATECTL_STATUS_LONG_RETRY)
    398  1.3.18.1   phil 		retries = status->long_retries;
    399  1.3.18.1   phil 
    400  1.3.18.1   phil 	amn->amn_txcnt++;
    401  1.3.18.1   phil 	if (status->status == IEEE80211_RATECTL_TX_SUCCESS)
    402  1.3.18.1   phil 		amn->amn_success++;
    403  1.3.18.1   phil 	amn->amn_retrycnt += retries;
    404  1.3.18.1   phil }
    405  1.3.18.1   phil 
    406  1.3.18.1   phil static void
    407  1.3.18.1   phil amrr_tx_update_cb(void *arg, struct ieee80211_node *ni)
    408  1.3.18.1   phil {
    409  1.3.18.1   phil 	struct ieee80211_ratectl_tx_stats *stats = arg;
    410  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    411  1.3.18.1   phil 	int txcnt, success, retrycnt;
    412  1.3.18.1   phil 
    413  1.3.18.1   phil 	txcnt = stats->nframes;
    414  1.3.18.1   phil 	success = stats->nsuccess;
    415  1.3.18.1   phil 	retrycnt = 0;
    416  1.3.18.1   phil 	if (stats->flags & IEEE80211_RATECTL_TX_STATS_RETRIES)
    417  1.3.18.1   phil 		retrycnt = stats->nretries;
    418  1.3.18.1   phil 
    419  1.3.18.1   phil 	amn->amn_txcnt += txcnt;
    420  1.3.18.1   phil 	amn->amn_success += success;
    421  1.3.18.1   phil 	amn->amn_retrycnt += retrycnt;
    422  1.3.18.1   phil }
    423  1.3.18.1   phil 
    424  1.3.18.1   phil /*
    425  1.3.18.1   phil  * Set tx count/retry statistics explicitly.  Intended for
    426  1.3.18.1   phil  * drivers that poll the device for statistics maintained
    427  1.3.18.1   phil  * in the device.
    428  1.3.18.1   phil  */
    429  1.3.18.1   phil static void
    430  1.3.18.1   phil amrr_tx_update(struct ieee80211vap *vap,
    431  1.3.18.1   phil     struct ieee80211_ratectl_tx_stats *stats)
    432  1.3.18.1   phil {
    433  1.3.18.1   phil 
    434  1.3.18.1   phil 	if (stats->flags & IEEE80211_RATECTL_TX_STATS_NODE)
    435  1.3.18.1   phil 		amrr_tx_update_cb(stats, stats->ni);
    436  1.3.18.1   phil 	else {
    437  1.3.18.1   phil 		ieee80211_iterate_nodes_vap(&vap->iv_ic->ic_sta, vap,
    438  1.3.18.1   phil 		    amrr_tx_update_cb, stats);
    439  1.3.18.1   phil 	}
    440  1.3.18.1   phil }
    441  1.3.18.1   phil 
    442  1.3.18.2   phil #ifdef notyet
    443  1.3.18.1   phil static int
    444  1.3.18.1   phil amrr_sysctl_interval(SYSCTL_HANDLER_ARGS)
    445  1.3.18.1   phil {
    446  1.3.18.1   phil 	struct ieee80211vap *vap = arg1;
    447  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    448  1.3.18.1   phil 	int msecs = ticks_to_msecs(amrr->amrr_interval);
    449  1.3.18.1   phil 	int error;
    450  1.3.18.1   phil 
    451  1.3.18.1   phil 	error = sysctl_handle_int(oidp, &msecs, 0, req);
    452  1.3.18.1   phil 	if (error || !req->newptr)
    453  1.3.18.1   phil 		return error;
    454  1.3.18.1   phil 	amrr_setinterval(vap, msecs);
    455  1.3.18.1   phil 	return 0;
    456  1.3.18.1   phil }
    457  1.3.18.2   phil #endif
    458  1.3.18.1   phil 
    459  1.3.18.1   phil static void
    460  1.3.18.1   phil amrr_sysctlattach(struct ieee80211vap *vap,
    461  1.3.18.1   phil     struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
    462  1.3.18.1   phil {
    463  1.3.18.2   phil #ifdef notyet
    464  1.3.18.1   phil 	struct ieee80211_amrr *amrr = vap->iv_rs;
    465  1.3.18.1   phil 
    466  1.3.18.1   phil 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
    467  1.3.18.1   phil 	    "amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap,
    468  1.3.18.1   phil 	    0, amrr_sysctl_interval, "I", "amrr operation interval (ms)");
    469  1.3.18.1   phil 	/* XXX bounds check values */
    470  1.3.18.1   phil 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
    471  1.3.18.1   phil 	    "amrr_max_sucess_threshold", CTLFLAG_RW,
    472  1.3.18.1   phil 	    &amrr->amrr_max_success_threshold, 0, "");
    473  1.3.18.1   phil 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
    474  1.3.18.1   phil 	    "amrr_min_sucess_threshold", CTLFLAG_RW,
    475  1.3.18.1   phil 	    &amrr->amrr_min_success_threshold, 0, "");
    476  1.3.18.2   phil #endif
    477  1.3.18.1   phil }
    478  1.3.18.1   phil 
    479  1.3.18.1   phil static void
    480  1.3.18.1   phil amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s)
    481  1.3.18.1   phil {
    482  1.3.18.1   phil 	int rate;
    483  1.3.18.1   phil 	struct ieee80211_amrr_node *amn = ni->ni_rctls;
    484  1.3.18.1   phil 	struct ieee80211_rateset *rs;
    485  1.3.18.1   phil 
    486  1.3.18.1   phil 	/* XXX TODO: check locking? */
    487  1.3.18.1   phil 
    488  1.3.18.1   phil 	/* XXX TODO: this should be a method */
    489  1.3.18.1   phil 	if (amrr_node_is_11n(ni)) {
    490  1.3.18.1   phil 		rs = (struct ieee80211_rateset *) &ni->ni_htrates;
    491  1.3.18.1   phil 		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
    492  1.3.18.1   phil 		sbuf_printf(s, "rate: MCS %d\n", rate);
    493  1.3.18.1   phil 	} else {
    494  1.3.18.1   phil 		rs = &ni->ni_rates;
    495  1.3.18.1   phil 		rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
    496  1.3.18.1   phil 		sbuf_printf(s, "rate: %d Mbit\n", rate / 2);
    497  1.3.18.1   phil 	}
    498  1.3.18.1   phil 
    499  1.3.18.1   phil 	sbuf_printf(s, "ticks: %d\n", amn->amn_ticks);
    500  1.3.18.1   phil 	sbuf_printf(s, "txcnt: %u\n", amn->amn_txcnt);
    501  1.3.18.1   phil 	sbuf_printf(s, "success: %u\n", amn->amn_success);
    502  1.3.18.1   phil 	sbuf_printf(s, "success_threshold: %u\n", amn->amn_success_threshold);
    503  1.3.18.1   phil 	sbuf_printf(s, "recovery: %u\n", amn->amn_recovery);
    504  1.3.18.1   phil 	sbuf_printf(s, "retry_cnt: %u\n", amn->amn_retrycnt);
    505       1.1  joerg }
    506  1.3.18.2   phil 
    507