From b9334f94acb26ea52b9d3333fa4289cceb91e937 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Fri, 1 Sep 2006 15:12:12 +0000 Subject: [PATCH] Implement a generic TX rate control algorithm framework in 802.11 layer. It is highly modulized so TX rate control algorithms can be added with ease. Only limited interfaces are exported for driver to use, so most of the WiFi drivers can be converted without too much trouble. It does not affect WiFi drivers which are unaware of the new framework yet. Also, the new framework allows TX rate control algorithm to be changed without touching the 802.11 state machine or reinitializing WiFi devices. Two TX rate control algorithms are factored out from ath(4) driver: 1) Onoe TX rate control algorithm, which is suitable for almost any kinds of WiFi NIC driver, especially for 11b devices. (*) 2) AMRR TX rate control algorithm, which should _only_ be used by the WiFi NIC which supports multi-rate retry. More information of this TX rate control algorithm is available at: http://www-sop.inria.fr/rapports/sophia/RR-5208.html In order to use the framework, individual WiFi driver needs to do following: 1) Tell the framework, which TX rate control algorithms it supports and which one to be used as the default, by setting up ieee80211com.ic_ratectl. 2) Call ieee80211_ratectl_newstate() in driver's own newstate() function. 3) When set up hardware TX descriptors, which normally contain TX rate related fields, instead of accessing ieee80211_node.ni_txrate directly, call ieee80211_ratectl_findrate() to get a rate set from the framework. 4) When TX completes, feed TX state (e.g. failure, number of retries) to the framework by calling ieee80211_ratectl_tx_complete(). Teach ifconfig(8) to print and set the TX rate control algorithm. # (*) There is no formal paper for this algorithm, but following two papers # have brief introduction of this TX rate control algorithm: # http://www-sop.inria.fr/rapports/sophia/RR-5208.html # http://www.pdos.lcs.mit.edu/papers/jbicket-ms.pdf --- sbin/ifconfig/ifconfig.8 | 16 +- sbin/ifconfig/ifieee80211.c | 42 +- sys/conf/files | 6 +- sys/config/LINT | 4 +- sys/i386/conf/LINT | 4 +- sys/netproto/802_11/Makefile | 4 +- sys/netproto/802_11/ieee80211.h | 4 +- sys/netproto/802_11/ieee80211_ioctl.h | 3 +- sys/netproto/802_11/ieee80211_node.h | 3 +- sys/netproto/802_11/ieee80211_ratectl.h | 113 ++++ sys/netproto/802_11/ieee80211_var.h | 8 +- sys/netproto/802_11/wlan/Makefile | 3 +- sys/netproto/802_11/wlan/ieee80211.c | 20 +- sys/netproto/802_11/wlan/ieee80211_ioctl.c | 14 +- sys/netproto/802_11/wlan/ieee80211_node.c | 23 +- sys/netproto/802_11/wlan/ieee80211_ratectl.c | 244 ++++++++ .../802_11/wlan/ieee80211_ratectl_none.c | 131 +++++ sys/netproto/802_11/wlan_ratectl/Makefile | 5 + .../802_11/wlan_ratectl/amrr/Makefile | 7 + .../amrr/ieee80211_ratectl_amrr.c | 547 ++++++++++++++++++ .../amrr/ieee80211_ratectl_amrr.h | 66 +++ .../802_11/wlan_ratectl/onoe/Makefile | 7 + .../onoe/ieee80211_ratectl_onoe.c | 535 +++++++++++++++++ .../onoe/ieee80211_ratectl_onoe.h | 65 +++ 24 files changed, 1855 insertions(+), 19 deletions(-) create mode 100644 sys/netproto/802_11/ieee80211_ratectl.h create mode 100644 sys/netproto/802_11/wlan/ieee80211_ratectl.c create mode 100644 sys/netproto/802_11/wlan/ieee80211_ratectl_none.c create mode 100644 sys/netproto/802_11/wlan_ratectl/Makefile create mode 100644 sys/netproto/802_11/wlan_ratectl/amrr/Makefile create mode 100644 sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c create mode 100644 sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h create mode 100644 sys/netproto/802_11/wlan_ratectl/onoe/Makefile create mode 100644 sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c create mode 100644 sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 4b2e6b420e..d32fc4733b 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -27,9 +27,9 @@ .\" .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.85 2004/07/27 09:51:49 yar Exp $ -.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.10 2006/05/18 14:24:34 sephe Exp $ +.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.11 2006/09/01 15:12:11 sephe Exp $ .\" -.Dd May 14, 2006 +.Dd September 1, 2006 .Dt IFCONFIG 8 .Os .Sh NAME @@ -848,6 +848,18 @@ capable; otherwise, the operating system will automatically attempt to reestablish communication. Manual mode is mostly useful when an application wants to control the selection of an access point. +.It Cm ratectl Ar algorithm +Set the TX rate control algorithm. +The set of valid +.Ar algorithm +is +.Cm onoe +(Onoe TX rate control algorithm) +and +.Cm amrr +(AMRR TX rate control algorithm). +.Ar Algorithm +names are case sensitive. .It Cm rtsthreshold Ar length Set the threshold for which transmitted frames are preceded by transmission of an diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c index 7376a82e1e..a8df1376ba 100644 --- a/sbin/ifconfig/ifieee80211.c +++ b/sbin/ifconfig/ifieee80211.c @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.9 2006/03/07 17:50:23 sam Exp $ - * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.12 2006/08/03 16:40:46 swildner Exp $ + * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.13 2006/09/01 15:12:11 sephe Exp $ */ /*- @@ -81,6 +81,7 @@ #include #include #include +#include #include #include @@ -670,6 +671,21 @@ set80211burst(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); } +static void +set80211ratectl(const char *val, int d, int s, const struct afswtch *rafp) +{ + int ratectl = 0; + + if (strcmp("onoe", val) == 0) + ratectl = IEEE80211_RATECTL_ONOE; + else if (strcmp("amrr", val) == 0) + ratectl = IEEE80211_RATECTL_AMRR; + else + errx(1, "unknown ratectl"); + + set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL); +} + static DECL_CMD_FUNC(set80211mcastrate, val, d) { @@ -1439,6 +1455,29 @@ ieee80211_status(int s) /* If we can't get the SSID, this isn't an 802.11 device. */ return; } + + ireq.i_type = IEEE80211_IOC_RATECTL; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + int lineb = 1; + + switch (ireq.i_val) { + case IEEE80211_RATECTL_ONOE: + printf("\tratectl: onoe"); + break; + case IEEE80211_RATECTL_AMRR: + printf("\tratectl: amrr"); + break; + default: + if (verbose) + printf("\tratectl: none"); + else + lineb = 0; + break; + } + if (lineb) + LINE_BREAK(); + } + num = 0; ireq.i_type = IEEE80211_IOC_NUMSSIDS; if (ioctl(s, SIOCG80211, &ireq) >= 0) @@ -1951,6 +1990,7 @@ static struct cmd ieee80211_cmds[] = { DEF_CMD_ARG("fragthreshold", set80211fragthreshold), DEF_CMD("burst", 1, set80211burst), DEF_CMD("-burst", 0, set80211burst), + DEF_CMD_ARG("ratectl", set80211ratectl) }; static struct afswtch af_ieee80211 = { .af_name = "af_ieee80211", diff --git a/sys/conf/files b/sys/conf/files index 14aa737b76..466a615ddc 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5 +1,5 @@ # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/sys/conf/files,v 1.137 2006/08/27 03:41:46 sephe Exp $ +# $DragonFly: src/sys/conf/files,v 1.138 2006/09/01 15:12:11 sephe Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -710,6 +710,8 @@ net/zlib.c optional ipsec netproto/802_11/wlan/ieee80211.c optional wlan netproto/802_11/wlan/ieee80211_crypto.c optional wlan netproto/802_11/wlan/ieee80211_crypto_none.c optional wlan +netproto/802_11/wlan/ieee80211_ratectl.c optional wlan +netproto/802_11/wlan/ieee80211_ratectl_none.c optional wlan netproto/802_11/wlan/ieee80211_dragonfly.c optional wlan netproto/802_11/wlan/ieee80211_input.c optional wlan netproto/802_11/wlan/ieee80211_ioctl.c optional wlan @@ -721,6 +723,8 @@ netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c optional wlan_ccmp netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c optional wlan_tkip netproto/802_11/wlan_wep/ieee80211_crypto_wep.c optional wlan_wep netproto/802_11/wlan_xauth/ieee80211_xauth.c optional wlan_xauth +netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c optional wlan_ratectl_onoe +netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c optional wlan_ratectl_amrr netproto/atalk/aarp.c optional netatalk netproto/atalk/at_control.c optional netatalk netproto/atalk/at_proto.c optional netatalk diff --git a/sys/config/LINT b/sys/config/LINT index b955c209cf..f4739864a2 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -3,7 +3,7 @@ # as much of the source tree as it can. # # $FreeBSD: src/sys/i386/conf/LINT,v 1.749.2.144 2003/06/04 17:56:59 sam Exp $ -# $DragonFly: src/sys/config/LINT,v 1.88 2006/08/27 03:43:15 sephe Exp $ +# $DragonFly: src/sys/config/LINT,v 1.89 2006/09/01 15:12:11 sephe Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1412,6 +1412,8 @@ device wlan_ccmp # 802.11 CCMP support device wlan_tkip # 802.11 TKIP support device wlan_wep # 802.11 WEP support device wlan_xauth # 802.11 WPA or 802.1x authentication for AP +device wlan_ratectl_onoe # 802.11 Onoe TX rate control algorithm +device wlan_ratectl_amrr # 802.11 AMRR TX rate control algorithm options WLCACHE # enables the signal-strength cache options WLDEBUG # enables verbose debugging output #device awi # AMD PCnetMobile diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 18df91e9b2..2e831bd75e 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -3,7 +3,7 @@ # as much of the source tree as it can. # # $FreeBSD: src/sys/i386/conf/LINT,v 1.749.2.144 2003/06/04 17:56:59 sam Exp $ -# $DragonFly: src/sys/i386/conf/Attic/LINT,v 1.88 2006/08/27 03:43:15 sephe Exp $ +# $DragonFly: src/sys/i386/conf/Attic/LINT,v 1.89 2006/09/01 15:12:11 sephe Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1412,6 +1412,8 @@ device wlan_ccmp # 802.11 CCMP support device wlan_tkip # 802.11 TKIP support device wlan_wep # 802.11 WEP support device wlan_xauth # 802.11 WPA or 802.1x authentication for AP +device wlan_ratectl_onoe # 802.11 Onoe TX rate control algorithm +device wlan_ratectl_amrr # 802.11 AMRR TX rate control algorithm options WLCACHE # enables the signal-strength cache options WLDEBUG # enables verbose debugging output #device awi # AMD PCnetMobile diff --git a/sys/netproto/802_11/Makefile b/sys/netproto/802_11/Makefile index ad5fc7d381..89992156bb 100644 --- a/sys/netproto/802_11/Makefile +++ b/sys/netproto/802_11/Makefile @@ -1,5 +1,5 @@ -# $DragonFly: src/sys/netproto/802_11/Makefile,v 1.5 2006/05/18 13:51:46 sephe Exp $ +# $DragonFly: src/sys/netproto/802_11/Makefile,v 1.6 2006/09/01 15:12:11 sephe Exp $ -SUBDIR= wlan wlan_acl wlan_ccmp wlan_tkip wlan_wep wlan_xauth +SUBDIR= wlan wlan_acl wlan_ccmp wlan_tkip wlan_wep wlan_xauth wlan_ratectl .include diff --git a/sys/netproto/802_11/ieee80211.h b/sys/netproto/802_11/ieee80211.h index b8f64a0010..edb860026a 100644 --- a/sys/netproto/802_11/ieee80211.h +++ b/sys/netproto/802_11/ieee80211.h @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211.h,v 1.9.2.1 2005/07/29 23:31:02 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/ieee80211.h,v 1.2 2006/05/18 13:51:46 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211.h,v 1.3 2006/09/01 15:12:11 sephe Exp $ */ #ifndef _NET80211_IEEE80211_H_ #define _NET80211_IEEE80211_H_ @@ -436,6 +436,8 @@ struct ieee80211_country_ie { #define IEEE80211_RATE_BASIC 0x80 #define IEEE80211_RATE_VAL 0x7f +#define IEEE80211_RS_RATE(rs, idx) \ + ((rs)->rs_rates[idx] & IEEE80211_RATE_VAL) /* EPR information element flags */ #define IEEE80211_ERP_NON_ERP_PRESENT 0x01 diff --git a/sys/netproto/802_11/ieee80211_ioctl.h b/sys/netproto/802_11/ieee80211_ioctl.h index e5e4cb5be0..2ba8cf1785 100644 --- a/sys/netproto/802_11/ieee80211_ioctl.h +++ b/sys/netproto/802_11/ieee80211_ioctl.h @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_ioctl.h,v 1.10.2.4 2005/12/22 19:18:23 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/ieee80211_ioctl.h,v 1.2 2006/05/18 13:51:46 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211_ioctl.h,v 1.3 2006/09/01 15:12:11 sephe Exp $ */ #ifndef _NET80211_IEEE80211_IOCTL_H_ #define _NET80211_IEEE80211_IOCTL_H_ @@ -446,6 +446,7 @@ struct ieee80211req { #define IEEE80211_IOC_MCAST_RATE 72 /* tx rate for mcast frames */ #define IEEE80211_IOC_FRAGTHRESHOLD 73 /* tx fragmentation threshold */ #define IEEE80211_IOC_BURST 75 /* packet bursting */ +#define IEEE80211_IOC_RATECTL 255 /* * Scan result data returned for IEEE80211_IOC_SCAN_RESULTS. diff --git a/sys/netproto/802_11/ieee80211_node.h b/sys/netproto/802_11/ieee80211_node.h index bd058f0a8a..b95103d6d2 100644 --- a/sys/netproto/802_11/ieee80211_node.h +++ b/sys/netproto/802_11/ieee80211_node.h @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_node.h,v 1.17.2.5 2006/03/13 03:05:47 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/ieee80211_node.h,v 1.2 2006/05/18 13:51:46 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211_node.h,v 1.3 2006/09/01 15:12:11 sephe Exp $ */ #ifndef _NET80211_IEEE80211_NODE_H_ #define _NET80211_IEEE80211_NODE_H_ @@ -147,6 +147,7 @@ struct ieee80211_node { int ni_txrate; /* index to ni_rates[] */ struct ifqueue ni_savedq; /* ps-poll queue */ struct ieee80211_nodestats ni_stats; /* per-node statistics */ + void *ni_rate_data; uint32_t ni_pad[8]; /* future expansion */ }; MALLOC_DECLARE(M_80211_NODE); diff --git a/sys/netproto/802_11/ieee80211_ratectl.h b/sys/netproto/802_11/ieee80211_ratectl.h new file mode 100644 index 0000000000..9991c50aad --- /dev/null +++ b/sys/netproto/802_11/ieee80211_ratectl.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Sepherosa Ziehau + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sys/netproto/802_11/ieee80211_ratectl.h,v 1.1 2006/09/01 15:12:11 sephe Exp $ + */ + +#ifndef _NET80211_IEEE80211_RATECTL_H +#define _NET80211_IEEE80211_RATECTL_H + +struct ieee80211_ratectl_state { + void *rc_st_ctx; + u_int rc_st_ratectl; /* see IEEE80211_RATECTL_ */ + uint32_t rc_st_ratectl_cap; /* see IEEE80211_RATECTL_CAP_ */ + void (*rc_st_change)(struct ieee80211com *, u_int, u_int); +}; + +struct ieee80211_ratectl_res { + int rc_res_rateidx; + int rc_res_tries; +}; + +struct ieee80211_ratectl { + const char *rc_name; + u_int rc_ratectl; /* see IEEE80211_RATECTL_ */ + + void *(*rc_attach)(struct ieee80211com *); + void (*rc_detach)(void *); + + void (*rc_data_alloc)(struct ieee80211_node *); + void (*rc_data_free)(struct ieee80211_node *); + void (*rc_data_dup)(const struct ieee80211_node *, + struct ieee80211_node *); + + void (*rc_newstate)(void *, enum ieee80211_state); + void (*rc_tx_complete)(void *, struct ieee80211_node *, int, + const struct ieee80211_ratectl_res[], + int, int, int, int); + void (*rc_newassoc)(void *, struct ieee80211_node *, int); + int (*rc_findrate)(void *, struct ieee80211_node *, int, + int[], int); +}; + +#define IEEE80211_RATECTL_NONE 0 +#define IEEE80211_RATECTL_ONOE 1 +#define IEEE80211_RATECTL_AMRR 2 +#define IEEE80211_RATECTL_MAX 3 + +#define IEEE80211_AMRR_RATEIDX_MAX 4 +#define IEEE80211_RATEIDX_MAX 5 + +#define IEEE80211_RATECTL_CAP(v) (1 << (v)) + +#define _IEEE80211_RATECTL_CAP(n) \ + IEEE80211_RATECTL_CAP(IEEE80211_RATECTL_##n) + +#define IEEE80211_RATECTL_CAP_NONE _IEEE80211_RATECTL_CAP(NONE) +#define IEEE80211_RATECTL_CAP_ONOE _IEEE80211_RATECTL_CAP(ONOE) +#define IEEE80211_RATECTL_CAP_AMRR _IEEE80211_RATECTL_CAP(AMRR) + +extern const struct ieee80211_ratectl ieee80211_ratectl_none; + +void ieee80211_ratectl_attach(struct ieee80211com *); +void ieee80211_ratectl_detach(struct ieee80211com *); + +void ieee80211_ratectl_register(const struct ieee80211_ratectl *); +void ieee80211_ratectl_unregister(const struct ieee80211_ratectl *); + +int ieee80211_ratectl_change(struct ieee80211com *, u_int); + +void ieee80211_ratectl_data_alloc(struct ieee80211_node *); +void ieee80211_ratectl_data_dup(const struct ieee80211_node *, + struct ieee80211_node *); +void ieee80211_ratectl_data_free(struct ieee80211_node *); + +void ieee80211_ratectl_newstate(struct ieee80211com *, + enum ieee80211_state); +void ieee80211_ratectl_tx_complete(struct ieee80211_node *, int, + const struct ieee80211_ratectl_res[], + int, int, int, int); +void ieee80211_ratectl_newassoc(struct ieee80211_node *, int); +int ieee80211_ratectl_findrate(struct ieee80211_node *, int, int[], int); + +#endif /* !_NET80211_IEEE80211_RATECTL_H */ diff --git a/sys/netproto/802_11/ieee80211_var.h b/sys/netproto/802_11/ieee80211_var.h index 97779561d2..30ded2d1d3 100644 --- a/sys/netproto/802_11/ieee80211_var.h +++ b/sys/netproto/802_11/ieee80211_var.h @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_var.h,v 1.22.2.11 2006/03/13 03:05:48 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/ieee80211_var.h,v 1.4 2006/08/04 15:42:27 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211_var.h,v 1.5 2006/09/01 15:12:11 sephe Exp $ */ #ifndef _NET80211_IEEE80211_VAR_H_ #define _NET80211_IEEE80211_VAR_H_ @@ -60,6 +60,7 @@ #include /* for ieee80211_stats */ #include #include +#include #define IEEE80211_TXPOWER_MAX 100 /* .5 dbM (XXX units?) */ #define IEEE80211_TXPOWER_MIN 0 /* kill radio */ @@ -214,6 +215,11 @@ struct ieee80211com { * is setup that the methods are safe to call. */ const struct ieee80211_aclator *ic_acl; + + /* + * Rate control state/configuration. + */ + struct ieee80211_ratectl_state ic_ratectl; void *ic_as; uint32_t ic_pad[56]; /* future expansion */ }; diff --git a/sys/netproto/802_11/wlan/Makefile b/sys/netproto/802_11/wlan/Makefile index 5d1c628021..37a39b9c68 100644 --- a/sys/netproto/802_11/wlan/Makefile +++ b/sys/netproto/802_11/wlan/Makefile @@ -1,8 +1,9 @@ -# $DragonFly: src/sys/netproto/802_11/wlan/Makefile,v 1.5 2006/05/18 13:51:46 sephe Exp $ +# $DragonFly: src/sys/netproto/802_11/wlan/Makefile,v 1.6 2006/09/01 15:12:11 sephe Exp $ KMOD = wlan SRCS = ieee80211.c ieee80211_ioctl.c ieee80211_node.c ieee80211_proto.c SRCS += ieee80211_crypto.c ieee80211_crypto_none.c +SRCS += ieee80211_ratectl.c ieee80211_ratectl_none.c SRCS += ieee80211_input.c ieee80211_output.c SRCS += ieee80211_dragonfly.c SRCS += bus_if.h device_if.h opt_inet.h opt_ipx.h diff --git a/sys/netproto/802_11/wlan/ieee80211.c b/sys/netproto/802_11/wlan/ieee80211.c index 6b8611ddca..00564df146 100644 --- a/sys/netproto/802_11/wlan/ieee80211.c +++ b/sys/netproto/802_11/wlan/ieee80211.c @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211.c,v 1.19.2.7 2006/03/11 19:25:23 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211.c,v 1.7 2006/06/28 21:03:51 swildner Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211.c,v 1.8 2006/09/01 15:12:11 sephe Exp $ */ /* @@ -209,6 +209,8 @@ ieee80211_ifattach(struct ieee80211com *ic) ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */ + ieee80211_ratectl_attach(ic); + /* * Install a default reset method for the ioctl support. * The driver is expected to fill this in before calling us. @@ -222,6 +224,17 @@ ieee80211_ifdetach(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; + /* + * XXX + * Certain rate control algorithm(e.g. onoe) may iterate node + * tables, which will assert serializer. + * In order to make the assertion work, hold serializer here. + * SHOULD BE REMOVED + */ + lwkt_serialize_enter(ifp->if_serializer); + ieee80211_ratectl_detach(ic); + lwkt_serialize_exit(ifp->if_serializer); + ieee80211_remove_vap(ic); ieee80211_sysctl_detach(ic); @@ -232,9 +245,8 @@ ieee80211_ifdetach(struct ieee80211com *ic) * XXX * ieee80211_node_detach() -> ieee80211_node_table_cleanup() * -> ieee80211_free_allnodes_locked() - * will assert the serializer - * In order to make the assertion work, hold serializer here - * + * will assert the serializer. + * In order to make the assertion work, hold serializer here. * SHOULD BE REMOVED */ lwkt_serialize_enter(ifp->if_serializer); diff --git a/sys/netproto/802_11/wlan/ieee80211_ioctl.c b/sys/netproto/802_11/wlan/ieee80211_ioctl.c index dcb0ef963b..a2212856a4 100644 --- a/sys/netproto/802_11/wlan/ieee80211_ioctl.c +++ b/sys/netproto/802_11/wlan/ieee80211_ioctl.c @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.25.2.11 2006/02/28 02:02:43 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_ioctl.c,v 1.2 2006/05/18 13:51:46 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_ioctl.c,v 1.3 2006/09/01 15:12:11 sephe Exp $ */ /* @@ -1510,6 +1510,9 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, case IEEE80211_IOC_BURST: ireq->i_val = (ic->ic_flags & IEEE80211_F_BURST) != 0; break; + case IEEE80211_IOC_RATECTL: + ireq->i_val = ic->ic_ratectl.rc_st_ratectl; + break; default: error = EINVAL; break; @@ -2428,6 +2431,15 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re ic->ic_flags &= ~IEEE80211_F_BURST; error = ENETRESET; /* XXX maybe not for station? */ break; + case IEEE80211_IOC_RATECTL: + if (ireq->i_val < 0 || ireq->i_val >= IEEE80211_RATECTL_MAX || + ireq->i_val == IEEE80211_RATECTL_NONE) { + error = EINVAL; + break; + } + + error = ieee80211_ratectl_change(ic, ireq->i_val); + break; default: error = EINVAL; break; diff --git a/sys/netproto/802_11/wlan/ieee80211_node.c b/sys/netproto/802_11/wlan/ieee80211_node.c index 44813c2087..44a372e5c2 100644 --- a/sys/netproto/802_11/wlan/ieee80211_node.c +++ b/sys/netproto/802_11/wlan/ieee80211_node.c @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.48.2.10 2006/03/13 03:05:47 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.3 2006/08/03 16:40:48 swildner Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.4 2006/09/01 15:12:11 sephe Exp $ */ #include @@ -372,6 +372,7 @@ copy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) nbss->ni_txpower = obss->ni_txpower; nbss->ni_vlan = obss->ni_vlan; nbss->ni_rsn = obss->ni_rsn; + ieee80211_ratectl_data_dup(obss, nbss); /* XXX statistics? */ } @@ -965,6 +966,8 @@ ieee80211_setup_node(struct ieee80211_node_table *nt, LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); ni->ni_table = nt; ni->ni_ic = ic; + + ieee80211_ratectl_data_alloc(ni); } struct ieee80211_node * @@ -1010,6 +1013,8 @@ ieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr) ni->ni_table = NULL; /* NB: pedantic */ ni->ni_ic = ic; + + ieee80211_ratectl_data_alloc(ni); } else { /* XXX msg */ ic->ic_stats.is_rx_nodealloc++; @@ -1108,8 +1113,12 @@ ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, if (ni != NULL) { /* XXX no rate negotiation; just dup */ ni->ni_rates = ic->ic_bss->ni_rates; + + ieee80211_ratectl_newassoc(ni, 1); + if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, 1); + /* XXX not right for 802.1x/WPA */ ieee80211_node_authorize(ni); if (ic->ic_opmode == IEEE80211_M_AHDEMO) { @@ -1299,8 +1308,12 @@ ieee80211_add_neighbor(struct ieee80211com *ic, ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */ if (ni != NULL) { ieee80211_init_neighbor(ni, wh, sp); + + ieee80211_ratectl_newassoc(ni, 1); + if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, 1); + /* XXX not right for 802.1x/WPA */ ieee80211_node_authorize(ni); } @@ -1570,6 +1583,8 @@ _ieee80211_free_node(struct ieee80211_node *ni) ni->ni_macaddr, ":", nt != NULL ? nt->nt_name : ""); + ieee80211_ratectl_data_free(ni); + IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); if (nt != NULL) { TAILQ_REMOVE(&nt->nt_node, ni, ni_list); @@ -1673,6 +1688,9 @@ node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) "%s: remove %p<%6D> from %s table, refcnt %d\n", __func__, ni, ni->ni_macaddr, ":", nt->nt_name, ieee80211_node_refcnt(ni)-1); + + ieee80211_ratectl_data_free(ni); + /* * Clear any entry in the unicast key mapping table. * We need to do it here so rx lookups don't find it @@ -2038,9 +2056,12 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "" ); + ieee80211_ratectl_newassoc(ni, newassoc); + /* give driver a chance to setup state like ni_txrate */ if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, newassoc); + ni->ni_inact_reload = ic->ic_inact_auth; ni->ni_inact = ni->ni_inact_reload; IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); diff --git a/sys/netproto/802_11/wlan/ieee80211_ratectl.c b/sys/netproto/802_11/wlan/ieee80211_ratectl.c new file mode 100644 index 0000000000..662fbdc9b7 --- /dev/null +++ b/sys/netproto/802_11/wlan/ieee80211_ratectl.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2006 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Sepherosa Ziehau + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_ratectl.c,v 1.1 2006/09/01 15:12:11 sephe Exp $ + */ + +#include +#include + +#include +#include +#include + +#include + +static const struct ieee80211_ratectl *ratectls[IEEE80211_RATECTL_MAX] = { + [IEEE80211_RATECTL_NONE] = &ieee80211_ratectl_none +}; + +static const char *ratectl_modname[IEEE80211_RATECTL_MAX] = { + [IEEE80211_RATECTL_ONOE] = "wlan_ratectl_onoe", + [IEEE80211_RATECTL_AMRR] = "wlan_ratectl_amrr" +}; + +void +ieee80211_ratectl_attach(struct ieee80211com *ic) +{ + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + u_int cur_ratectl = rc_st->rc_st_ratectl; + + rc_st->rc_st_ratectl_cap |= IEEE80211_RATECTL_CAP_NONE; + rc_st->rc_st_ratectl = IEEE80211_RATECTL_NONE; + + ieee80211_ratectl_change(ic, cur_ratectl); +} + +void +ieee80211_ratectl_detach(struct ieee80211com *ic) +{ + ieee80211_ratectl_change(ic, IEEE80211_RATECTL_NONE); +} + +void +ieee80211_ratectl_register(const struct ieee80211_ratectl *rc) +{ + /* + * Sanity checks + */ + if (rc->rc_ratectl >= IEEE80211_RATECTL_MAX) { + printf("%s: rate control %s has an invalid index %d\n", + __func__, rc->rc_name, rc->rc_ratectl); + return; + } + if (ratectls[rc->rc_ratectl] != NULL && + ratectls[rc->rc_ratectl] != rc) { + printf("%s: rate control index %d is registered by %s\n", + __func__, rc->rc_ratectl, + ratectls[rc->rc_ratectl]->rc_name); + return; + } + + ratectls[rc->rc_ratectl] = rc; +} + +void +ieee80211_ratectl_unregister(const struct ieee80211_ratectl *rc) +{ + /* + * Sanity checks + */ + if (rc->rc_ratectl >= IEEE80211_RATECTL_MAX) { + printf("%s: rate control %s has an invalid index %d\n", + __func__, rc->rc_name, rc->rc_ratectl); + return; + } + if (ratectls[rc->rc_ratectl] != NULL && + ratectls[rc->rc_ratectl] != rc) { + printf("%s: rate control index %d is registered by %s\n", + __func__, rc->rc_ratectl, + ratectls[rc->rc_ratectl]->rc_name); + return; + } + + /* + * Indiviual rate control module MUST maintain reference count itself. + */ + ratectls[rc->rc_ratectl] = NULL; +} + +int +ieee80211_ratectl_change(struct ieee80211com *ic, u_int rc_idx) +{ + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc, *rc_old; + + if (rc_idx == rc_st->rc_st_ratectl) { + /* Nothing need to be changed */ + return 0; + } + + if ((IEEE80211_RATECTL_CAP(rc_idx) & rc_st->rc_st_ratectl_cap) == 0) { + /* We are not capable to do requested rate control */ + return EOPNOTSUPP; + } + + rc = ratectls[rc_idx]; + if (rc == NULL) { + /* Try load the rate control module */ + ieee80211_load_module(ratectl_modname[rc_idx]); + + /* + * If rate control module loaded it should immediately + * call ieee80211_ratectl_register() which will fill in + * the entry in the 'ratectls' array. + */ + rc = ratectls[rc_idx]; + if (rc == NULL) { + printf("%s: can't load requested rate control module", + __func__); + return EOPNOTSUPP; + } + } + + /* Detach old rate control */ + rc_old = ratectls[rc_st->rc_st_ratectl]; + rc_old->rc_detach(rc_st->rc_st_ctx); + + if (rc_st->rc_st_change != NULL) + rc_st->rc_st_change(ic, rc_st->rc_st_ratectl, rc_idx); + + /* Attach new rate control */ + rc_st->rc_st_ratectl = rc_idx; + rc_st->rc_st_ctx = rc->rc_attach(ic); + + return 0; +} + +void +ieee80211_ratectl_data_alloc(struct ieee80211_node *ni) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + rc->rc_data_alloc(ni); +} + +void +ieee80211_ratectl_data_dup(const struct ieee80211_node *oni, + struct ieee80211_node *nni) +{ + struct ieee80211com *ic = oni->ni_ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + rc->rc_data_dup(oni, nni); +} + +void +ieee80211_ratectl_data_free(struct ieee80211_node *ni) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + rc->rc_data_free(ni); +} + +void +ieee80211_ratectl_newstate(struct ieee80211com *ic, enum ieee80211_state state) +{ + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + rc->rc_newstate(rc_st->rc_st_ctx, state); +} + +void +ieee80211_ratectl_tx_complete(struct ieee80211_node *ni, int frame_len, + const struct ieee80211_ratectl_res res[], + int res_len, int short_retries, int long_retries, + int is_fail) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + rc->rc_tx_complete(rc_st->rc_st_ctx, ni, frame_len, res, res_len, + long_retries, short_retries, is_fail); +} + +void +ieee80211_ratectl_newassoc(struct ieee80211_node *ni, int is_new) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + rc->rc_newassoc(rc_st->rc_st_ctx, ni, is_new); +} + +int +ieee80211_ratectl_findrate(struct ieee80211_node *ni, int frame_len, + int rateidx[], int rateidx_len) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl]; + + KKASSERT(rateidx_len > 0); + + return rc->rc_findrate(rc_st->rc_st_ctx, ni, frame_len, + rateidx, rateidx_len); +} diff --git a/sys/netproto/802_11/wlan/ieee80211_ratectl_none.c b/sys/netproto/802_11/wlan/ieee80211_ratectl_none.c new file mode 100644 index 0000000000..cf6ea708e6 --- /dev/null +++ b/sys/netproto/802_11/wlan/ieee80211_ratectl_none.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2006 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Sepherosa Ziehau + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_ratectl_none.c,v 1.1 2006/09/01 15:12:11 sephe Exp $ + */ + +#include +#include + +#include +#include +#include + +#include + +static void *none_ratectl_attach(struct ieee80211com *); +static void none_ratectl_detach(void *); +static void none_ratectl_data_alloc(struct ieee80211_node *); +static void none_ratectl_data_free(struct ieee80211_node *); +static void none_ratectl_data_dup(const struct ieee80211_node *, + struct ieee80211_node *); +static void none_ratectl_newstate(void *, enum ieee80211_state); +static void none_ratectl_tx_complete(void *, struct ieee80211_node *, + int, const struct ieee80211_ratectl_res[], + int, int, int, int); +static void none_ratectl_newassoc(void *, struct ieee80211_node *, int); +static int none_ratectl_findrate(void *, struct ieee80211_node *, int, + int[], int); + +const struct ieee80211_ratectl ieee80211_ratectl_none = { + .rc_name = "none", + .rc_ratectl = IEEE80211_RATECTL_NONE, + .rc_attach = none_ratectl_attach, + .rc_detach = none_ratectl_detach, + .rc_data_alloc = none_ratectl_data_alloc, + .rc_data_free = none_ratectl_data_free, + .rc_data_dup = none_ratectl_data_dup, + .rc_newstate = none_ratectl_newstate, + .rc_tx_complete = none_ratectl_tx_complete, + .rc_newassoc = none_ratectl_newassoc, + .rc_findrate = none_ratectl_findrate +}; + +static void * +none_ratectl_attach(struct ieee80211com *ic __unused) +{ + return NULL; +} + +static void +none_ratectl_detach(void *arg __unused) +{ +} + +static void +none_ratectl_data_alloc(struct ieee80211_node *ni __unused) +{ +} + +static void +none_ratectl_data_free(struct ieee80211_node *ni __unused) +{ +} + +static void +none_ratectl_data_dup(const struct ieee80211_node *oni __unused, + struct ieee80211_node *nni __unused) +{ +} + +static void +none_ratectl_newstate(void *arg __unused, enum ieee80211_state state __unused) +{ +} + +static void +none_ratectl_tx_complete(void *arg __unused, struct ieee80211_node *ni __unused, + int frame_len __unused, + const struct ieee80211_ratectl_res res[] __unused, + int res_len __unused, + int short_retries __unused, int long_retries __unused, + int is_fail __unused) +{ +} + +static void +none_ratectl_newassoc(void *arg __unused, struct ieee80211_node *ni __unused, + int is_new __unused) +{ +} + +static int +none_ratectl_findrate(void * arg __unused, struct ieee80211_node *ni, + int frame_len __unused, int rateidx[], int rateidx_len) +{ + int i; + + for (i = 0; i < rateidx_len; ++i) + rateidx[i] = ni->ni_txrate; + return rateidx_len; +} diff --git a/sys/netproto/802_11/wlan_ratectl/Makefile b/sys/netproto/802_11/wlan_ratectl/Makefile new file mode 100644 index 0000000000..7a5f2c8431 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/Makefile @@ -0,0 +1,5 @@ +# $DragonFly: src/sys/netproto/802_11/wlan_ratectl/Makefile,v 1.1 2006/09/01 15:12:11 sephe Exp $ + +SUBDIR= onoe amrr + +.include diff --git a/sys/netproto/802_11/wlan_ratectl/amrr/Makefile b/sys/netproto/802_11/wlan_ratectl/amrr/Makefile new file mode 100644 index 0000000000..2bb12af111 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/amrr/Makefile @@ -0,0 +1,7 @@ +# $DragonFly: src/sys/netproto/802_11/wlan_ratectl/amrr/Makefile,v 1.1 2006/09/01 15:12:12 sephe Exp $ + +KMOD = wlan_ratectl_amrr +SRCS = ieee80211_ratectl_amrr.c +KMODDEPS= wlan + +.include diff --git a/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c b/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c new file mode 100644 index 0000000000..393fa66f9f --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2004 INRIA + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD: src/sys/dev/ath/ath_rate/amrr/amrr.c,v 1.8.2.3 2006/02/24 19:51:11 sam Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c,v 1.1 2006/09/01 15:12:12 sephe Exp $ + */ + +/* + * AMRR rate control. See: + * http://www-sop.inria.fr/rapports/sophia/RR-5208.html + * "IEEE 802.11 Rate Adaptation: A Practical Approach" by + * Mathieu Lacage, Hossein Manshaei, Thierry Turletti + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define AMRR_DEBUG +#ifdef AMRR_DEBUG +#define DPRINTF(asc, lv, fmt, ...) do { \ + if ((asc)->debug >= lv) \ + printf(fmt, __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(asc, lv, fmt, ...) +#endif + +static void *amrr_attach(struct ieee80211com *); +static void amrr_detach(void *); +static void amrr_data_alloc(struct ieee80211_node *); +static void amrr_data_free(struct ieee80211_node *); +static void amrr_data_dup(const struct ieee80211_node *, + struct ieee80211_node *); +static void amrr_newstate(void *, enum ieee80211_state); +static void amrr_tx_complete(void *, struct ieee80211_node *, int, + const struct ieee80211_ratectl_res[], + int, int, int, int); +static void amrr_newassoc(void *, struct ieee80211_node *, int); +static int amrr_findrate(void *, struct ieee80211_node *, int, + int[], int); + +static void amrr_sysctl_attach(struct amrr_softc *); +static void amrr_update(struct amrr_softc *, struct ieee80211_node *, int); +static void amrr_start(struct amrr_softc *, struct ieee80211_node *); +static void amrr_tick(void *); +static void amrr_ratectl(void *, struct ieee80211_node *); + +static const struct ieee80211_ratectl amrr = { + .rc_name = "amrr", + .rc_ratectl = IEEE80211_RATECTL_AMRR, + .rc_attach = amrr_attach, + .rc_detach = amrr_detach, + .rc_data_alloc = amrr_data_alloc, + .rc_data_free = amrr_data_free, + .rc_data_dup = amrr_data_dup, + .rc_newstate = amrr_newstate, + .rc_tx_complete = amrr_tx_complete, + .rc_newassoc = amrr_newassoc, + .rc_findrate = amrr_findrate +}; + +static u_int amrr_nrefs; + +MALLOC_DEFINE(M_AMRR_RATECTL_DATA, "amrr_ratectl_data", + "amrr rate control data"); + +static int +amrr_findrate(void *arg __unused, struct ieee80211_node *ni, + int frame_len __unused, int rateidx[], int rateidx_len) +{ + int i, rate_idx = ni->ni_txrate; + + for (i = 0; i < rateidx_len && i < IEEE80211_AMRR_RATEIDX_MAX; ++i) { + if (rate_idx < 0) + break; + rateidx[i] = rate_idx--; + } + if (rateidx_len > 1) + rateidx[rateidx_len - 1] = 0; + return i; +} + +static void +amrr_tx_complete(void *arg __unused, struct ieee80211_node *ni, + int frame_len __unused, + const struct ieee80211_ratectl_res res[], + int res_len, int short_retries __unused, + int long_retries __unused, int is_fail) +{ + struct amrr_data *ad = ni->ni_rate_data; + int i; + + if (ad == NULL) + return; + + for (i = 0; i < res_len && i < IEEE80211_AMRR_RATEIDX_MAX; ++i) + ad->ad_tx_try_cnt[i]++; + if (is_fail) + ad->ad_tx_failure_cnt++; +} + +static void +amrr_newassoc(void *arg, struct ieee80211_node *ni, int isnew) +{ + if (isnew) + amrr_start(arg, ni); +} + +/* + * The code below assumes that we are dealing with hardware multi rate retry + * I have no idea what will happen if you try to use this module with another + * type of hardware. Your machine might catch fire or it might work with + * horrible performance... + */ +static void +amrr_update(struct amrr_softc *asc, struct ieee80211_node *ni, int rate) +{ + struct amrr_data *ad = ni->ni_rate_data; + + DPRINTF(asc, 5, "%s: set xmit rate for %6D to %dM\n", + __func__, ni->ni_macaddr, ":", + ni->ni_rates.rs_nrates > 0 ? + IEEE80211_RS_RATE(&ni->ni_rates, rate) / 2 : 0); + + ni->ni_txrate = rate; + + if (ad == NULL) { + amrr_data_alloc(ni); + ad = ni->ni_rate_data; + if (ad == NULL) + return; + } + + ad->ad_tx_try_cnt[0] = 0; + ad->ad_tx_try_cnt[1] = 0; + ad->ad_tx_try_cnt[2] = 0; + ad->ad_tx_try_cnt[3] = 0; + ad->ad_tx_failure_cnt = 0; + ad->ad_success = 0; + ad->ad_recovery = 0; + ad->ad_success_threshold = asc->min_success_threshold; +} + +/* + * Set the starting transmit rate for a node. + */ +static void +amrr_start(struct amrr_softc *asc, struct ieee80211_node *ni) +{ +#define RATE(_ix) IEEE80211_RS_RATE(&ni->ni_rates, (_ix)) + struct ieee80211com *ic = asc->ic; + int srate; + + KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); + + if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { + /* + * For adhoc or ibss mode, start from the lowest rate. + */ + if (ic->ic_opmode == IEEE80211_M_AHDEMO || + ic->ic_opmode == IEEE80211_M_IBSS) { + amrr_update(asc, ni, 0); + return; + } + + /* + * No fixed rate is requested. For 11b start with + * the highest negotiated rate; otherwise, for 11g + * and 11a, we start "in the middle" at 24Mb or 36Mb. + */ + srate = ni->ni_rates.rs_nrates - 1; + if (ic->ic_curmode != IEEE80211_MODE_11B) { + /* + * Scan the negotiated rate set to find the + * closest rate. + */ + /* NB: the rate set is assumed sorted */ + for (; srate >= 0 && RATE(srate) > 72; srate--) + ; + KASSERT(srate >= 0, ("bogus rate set")); + } + } else { + /* + * A fixed rate is to be used; ic_fixed_rate is an + * index into the supported rate set. Convert this + * to the index into the negotiated rate set for + * the node. We know the rate is there because the + * rate set is checked when the station associates. + */ + const struct ieee80211_rateset *rs = + &ic->ic_sup_rates[ic->ic_curmode]; + int r = IEEE80211_RS_RATE(rs, ic->ic_fixed_rate); + + /* NB: the rate set is assumed sorted */ + srate = ni->ni_rates.rs_nrates - 1; + for (; srate >= 0 && RATE(srate) != r; srate--) + ; + KASSERT(srate >= 0, + ("fixed rate %d not in rate set", ic->ic_fixed_rate)); + } + amrr_update(asc, ni, srate); +#undef RATE +} + +static void +amrr_rate_cb(void *arg, struct ieee80211_node *ni) +{ + amrr_update(arg, ni, 0); +} + +/* + * Reset the rate control state for each 802.11 state transition. + */ +static void +amrr_newstate(void *arg, enum ieee80211_state state) +{ + struct amrr_softc *asc = arg; + struct ieee80211com *ic = asc->ic; + struct ieee80211_node *ni; + + if (state == IEEE80211_S_INIT) { + callout_stop(&asc->timer); + return; + } + + if (ic->ic_opmode == IEEE80211_M_STA) { + /* + * Reset local xmit state; this is really only + * meaningful when operating in station mode. + */ + ni = ic->ic_bss; + if (state == IEEE80211_S_RUN) + amrr_start(asc, ni); + else + amrr_update(asc, ni, 0); + } else { + /* + * When operating as a station the node table holds + * the AP's that were discovered during scanning. + * For any other operating mode we want to reset the + * tx rate state of each node. + */ + ieee80211_iterate_nodes(&ic->ic_sta, amrr_rate_cb, asc); + amrr_update(asc, ic->ic_bss, 0); + } + if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE && + state == IEEE80211_S_RUN) { + int interval; + + /* + * Start the background rate control thread if we + * are not configured to use a fixed xmit rate. + */ + interval = asc->interval; + if (ic->ic_opmode == IEEE80211_M_STA) + interval /= 2; + callout_reset(&asc->timer, (interval * hz) / 1000, + amrr_tick, asc); + } +} + +/* + * Examine and potentially adjust the transmit rate. + */ +static void +amrr_ratectl(void *arg, struct ieee80211_node *ni) +{ + struct amrr_softc *asc = arg; + struct amrr_data *ad = ni->ni_rate_data; + int old_rate; + + if (ad == NULL) { + /* We are not ready to go, set TX rate to lowest one */ + ni->ni_txrate = 0; + return; + } + +#define is_success(ad) \ +(ad->ad_tx_try_cnt[1] < (ad->ad_tx_try_cnt[0] / 10)) +#define is_enough(ad) \ +(ad->ad_tx_try_cnt[0] > 10) +#define is_failure(ad) \ +(ad->ad_tx_try_cnt[1] > (ad->ad_tx_try_cnt[0] / 3)) +#define is_max_rate(ni) \ +((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates) +#define is_min_rate(ni) \ +(ni->ni_txrate == 0) + + old_rate = ni->ni_txrate; + + DPRINTF(asc, 10, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- " + "threshold: %d\n", + ad->ad_tx_try_cnt[0], + ad->ad_tx_try_cnt[1], + ad->ad_tx_try_cnt[2], + ad->ad_tx_try_cnt[3], + ad->ad_success_threshold); + + if (is_success(ad) && is_enough(ad)) { + ad->ad_success++; + if (ad->ad_success == ad->ad_success_threshold && + !is_max_rate(ni)) { + ad->ad_recovery = 1; + ad->ad_success = 0; + ni->ni_txrate++; + DPRINTF(asc, 5, "increase rate to %d\n", ni->ni_txrate); + } else { + ad->ad_recovery = 0; + } + } else if (is_failure(ad)) { + ad->ad_success = 0; + if (!is_min_rate(ni)) { + if (ad->ad_recovery) { + /* recovery failure. */ + ad->ad_success_threshold *= 2; + ad->ad_success_threshold = + min(ad->ad_success_threshold, + (u_int)asc->max_success_threshold); + DPRINTF(asc, 5, "decrease rate recovery thr: " + "%d\n", ad->ad_success_threshold); + } else { + /* simple failure. */ + ad->ad_success_threshold = + asc->min_success_threshold; + DPRINTF(asc, 5, "decrease rate normal thr: " + "%d\n", ad->ad_success_threshold); + } + ad->ad_recovery = 0; + ni->ni_txrate--; + } else { + ad->ad_recovery = 0; + } + } + if (is_enough(ad) || old_rate != ni->ni_txrate) { + /* reset counters. */ + ad->ad_tx_try_cnt[0] = 0; + ad->ad_tx_try_cnt[1] = 0; + ad->ad_tx_try_cnt[2] = 0; + ad->ad_tx_try_cnt[3] = 0; + ad->ad_tx_failure_cnt = 0; + } + if (old_rate != ni->ni_txrate) + amrr_update(asc, ni, ni->ni_txrate); +} + +static void +amrr_tick(void *arg) +{ + struct amrr_softc *asc = arg; + struct ieee80211com *ic = asc->ic; + struct ifnet *ifp = &ic->ic_if; + int interval; + + lwkt_serialize_enter(ifp->if_serializer); + + if (ifp->if_flags & IFF_RUNNING) { + if (ic->ic_opmode == IEEE80211_M_STA) + amrr_ratectl(asc, ic->ic_bss); /* NB: no reference */ + else + ieee80211_iterate_nodes(&ic->ic_sta, amrr_ratectl, asc); + } + interval = asc->interval; + if (ic->ic_opmode == IEEE80211_M_STA) + interval /= 2; + callout_reset(&asc->timer, (interval * hz) / 1000, amrr_tick, asc); + + lwkt_serialize_exit(ifp->if_serializer); +} + +static void +amrr_sysctl_attach(struct amrr_softc *asc) +{ + asc->debug = 0; + asc->interval = 1000; + asc->max_success_threshold = 10; + asc->min_success_threshold = 1; + + sysctl_ctx_init(&asc->sysctl_ctx); + asc->sysctl_oid = SYSCTL_ADD_NODE(&asc->sysctl_ctx, + SYSCTL_CHILDREN(asc->ic->ic_sysctl_oid), + OID_AUTO, "amrr_ratectl", CTLFLAG_RD, 0, ""); + if (asc->sysctl_oid == NULL) { + printf("wlan_ratectl_amrr: create sysctl tree failed\n"); + return; + } + + SYSCTL_ADD_INT(&asc->sysctl_ctx, SYSCTL_CHILDREN(asc->sysctl_oid), + OID_AUTO, "interval", CTLFLAG_RW, + &asc->interval, 0, + "rate control: operation interval (ms)"); + + /* XXX bounds check values */ + SYSCTL_ADD_INT(&asc->sysctl_ctx, SYSCTL_CHILDREN(asc->sysctl_oid), + OID_AUTO, "max_sucess_threshold", CTLFLAG_RW, + &asc->max_success_threshold, 0, ""); + + SYSCTL_ADD_INT(&asc->sysctl_ctx, SYSCTL_CHILDREN(asc->sysctl_oid), + OID_AUTO, "min_sucess_threshold", CTLFLAG_RW, + &asc->min_success_threshold, 0, ""); + + SYSCTL_ADD_INT(&asc->sysctl_ctx, SYSCTL_CHILDREN(asc->sysctl_oid), + OID_AUTO, "debug", CTLFLAG_RW, + &asc->debug, 0, "debug level"); +} + +static void * +amrr_attach(struct ieee80211com *ic) +{ + struct amrr_softc *asc; + + amrr_nrefs++; + + asc = malloc(sizeof(struct amrr_softc), M_DEVBUF, M_WAITOK | M_ZERO); + + asc->ic = ic; + callout_init(&asc->timer); + amrr_sysctl_attach(asc); + + amrr_newstate(asc, ic->ic_state); + + return asc; +} + +static void +_amrr_data_free(void *arg __unused, struct ieee80211_node *ni) +{ + amrr_data_free(ni); +} + +void +amrr_detach(void *arg) +{ + struct amrr_softc *asc = arg; + struct ieee80211com *ic = asc->ic; + + amrr_newstate(asc, IEEE80211_S_INIT); + + ieee80211_iterate_nodes(&ic->ic_sta, _amrr_data_free, NULL); + ieee80211_iterate_nodes(&ic->ic_scan, _amrr_data_free, NULL); + + if (asc->sysctl_oid != NULL) + sysctl_ctx_free(&asc->sysctl_ctx); + free(asc, M_DEVBUF); + + amrr_nrefs--; +} + +static void +amrr_data_free(struct ieee80211_node *ni) +{ + if (ni->ni_rate_data != NULL) { + free(ni->ni_rate_data, M_AMRR_RATECTL_DATA); + ni->ni_rate_data = NULL; + } +} + +static void +amrr_data_alloc(struct ieee80211_node *ni) +{ + KKASSERT(ni->ni_rate_data == NULL); + ni->ni_rate_data = malloc(sizeof(struct amrr_data), + M_AMRR_RATECTL_DATA, M_NOWAIT | M_ZERO); +} + +static void +amrr_data_dup(const struct ieee80211_node *oni, struct ieee80211_node *nni) +{ + if (oni->ni_rate_data == NULL || nni->ni_rate_data == NULL) + return; + + bcopy(oni->ni_rate_data, nni->ni_rate_data, sizeof(struct amrr_data)); +} + +/* + * Module glue. + */ +static int +amrr_modevent(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + ieee80211_ratectl_register(&amrr); + return 0; + case MOD_UNLOAD: + if (amrr_nrefs) { + printf("wlan_ratectl_amrr: still in use " + "(%u dynamic refs)\n", amrr_nrefs); + return EBUSY; + } + ieee80211_ratectl_unregister(&amrr); + return 0; + } + return EINVAL; +} + +static moduledata_t amrr_mod = { + "wlan_ratectl_amrr", + amrr_modevent, + 0 +}; +DECLARE_MODULE(wlan_ratectl_amrr, amrr_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(wlan_ratectl_amrr, 1); +MODULE_DEPEND(wlan_ratectl_amrr, wlan, 1, 1, 1); diff --git a/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h b/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h new file mode 100644 index 0000000000..7f6b9df131 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004 INRIA + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD: src/sys/dev/ath/ath_rate/amrr/amrr.h,v 1.2 2004/12/31 22:41:45 sam Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/amrr/Attic/ieee80211_ratectl_amrr.h,v 1.1 2006/09/01 15:12:12 sephe Exp $ + */ + +#ifndef _IEEE80211_RATECTL_AMRR_H +#define _IEEE80211_RATECTL_AMRR_H + +struct amrr_softc { + struct ieee80211com *ic; + struct callout timer; /* periodic timer */ + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_oid; + int interval; /* unit: ms */ + int max_success_threshold; + int min_success_threshold; + int debug; +}; + +struct amrr_data { + /* AMRR statistics for this node */ + u_int ad_tx_try_cnt[IEEE80211_AMRR_RATEIDX_MAX]; + u_int ad_tx_failure_cnt; + + /* AMRR algorithm state for this node */ + u_int ad_success_threshold; + u_int ad_success; + u_int ad_recovery; +}; + +#endif /* !_IEEE80211_RATECTL_AMRR_H */ diff --git a/sys/netproto/802_11/wlan_ratectl/onoe/Makefile b/sys/netproto/802_11/wlan_ratectl/onoe/Makefile new file mode 100644 index 0000000000..74968848cb --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/onoe/Makefile @@ -0,0 +1,7 @@ +# $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/Makefile,v 1.1 2006/09/01 15:12:12 sephe Exp $ + +KMOD = wlan_ratectl_onoe +SRCS = ieee80211_ratectl_onoe.c +KMODDEPS= wlan + +.include diff --git a/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c b/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c new file mode 100644 index 0000000000..fe26761ad2 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.c,v 1.8.2.3 2006/02/24 19:51:11 sam Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c,v 1.1 2006/09/01 15:12:12 sephe Exp $ + */ + +/* + * Atsushi Onoe's rate control algorithm. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define ONOE_DEBUG + +#ifdef ONOE_DEBUG +#define DPRINTF(osc, lv, fmt, ...) do { \ + if ((osc)->debug >= lv) \ + printf(fmt, __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(osc, lv, fmt, ...) +#endif + +/* + * Default parameters for the rate control algorithm. These are + * all tunable with sysctls. The rate controller runs periodically + * (each ath_rateinterval ms) analyzing transmit statistics for each + * neighbor/station (when operating in station mode this is only the AP). + * If transmits look to be working well over a sampling period then + * it gives a "raise rate credit". If transmits look to not be working + * well than it deducts a credit. If the credits cross a threshold then + * the transmit rate is raised. Various error conditions force the + * the transmit rate to be dropped. + * + * The decision to issue/deduct a credit is based on the errors and + * retries accumulated over the sampling period. ath_rate_raise defines + * the percent of retransmits for which a credit is issued/deducted. + * ath_rate_raise_threshold defines the threshold on credits at which + * the transmit rate is increased. + * + * XXX this algorithm is flawed. + */ + +static void *onoe_attach(struct ieee80211com *); +static void onoe_detach(void *); +static void onoe_data_free(struct ieee80211_node *); +static void onoe_data_alloc(struct ieee80211_node *); +static void onoe_data_dup(const struct ieee80211_node *, + struct ieee80211_node *); +static void onoe_newstate(void *, enum ieee80211_state); +static void onoe_tx_complete(void *, struct ieee80211_node *, int, + const struct ieee80211_ratectl_res[], + int, int, int, int); +static void onoe_newassoc(void *, struct ieee80211_node *, int); +static int onoe_findrate(void *, struct ieee80211_node *, int, + int[], int); + +static void onoe_sysctl_attach(struct onoe_softc *); +static void onoe_update(struct onoe_softc *, struct ieee80211_node *, int); +static void onoe_start(struct onoe_softc *, struct ieee80211_node *); +static void onoe_tick(void *); +static void onoe_ratectl(void *, struct ieee80211_node *); + +static const struct ieee80211_ratectl onoe = { + .rc_name = "onoe", + .rc_ratectl = IEEE80211_RATECTL_ONOE, + .rc_attach = onoe_attach, + .rc_detach = onoe_detach, + .rc_data_alloc = onoe_data_alloc, + .rc_data_free = onoe_data_free, + .rc_data_dup = onoe_data_dup, + .rc_newstate = onoe_newstate, + .rc_tx_complete = onoe_tx_complete, + .rc_newassoc = onoe_newassoc, + .rc_findrate = onoe_findrate +}; + +static u_int onoe_nrefs; + +MALLOC_DEFINE(M_ONOE_RATECTL_DATA, "onoe_ratectl_data", + "onoe rate control data"); + +static void +onoe_tx_complete(void *arg __unused, struct ieee80211_node *ni, + int frame_len __unused, + const struct ieee80211_ratectl_res res[] __unused, + int res_len __unused, + int short_retries, int long_retries, int is_fail) +{ + struct onoe_data *od = ni->ni_rate_data; + + if (od == NULL) + return; + + if (is_fail) + od->od_tx_err++; + else + od->od_tx_ok++; + + od->od_tx_retr += long_retries + short_retries; +} + +static void +onoe_newassoc(void *arg, struct ieee80211_node *ni, int is_new) +{ + if (is_new) + onoe_start(arg, ni); +} + +static int +onoe_findrate(void *arg __unused, struct ieee80211_node *ni, + int frame_len __unused, int rateidx[], int rateidx_len) +{ + int i, rate_idx = ni->ni_txrate; + + for (i = 0; i < rateidx_len; ++i) { + if (rate_idx < 0) + break; + rateidx[i] = rate_idx--; + } + if (rateidx_len > 1) + rateidx[rateidx_len - 1] = 0; + return i; +} + +static void +onoe_update(struct onoe_softc *osc, struct ieee80211_node *ni, int nrate) +{ + struct onoe_data *od = ni->ni_rate_data; + + DPRINTF(osc, 1, "%s: set xmit rate for %6D to %dM\n", __func__, + ni->ni_macaddr, ":", + ni->ni_rates.rs_nrates > 0 ? + IEEE80211_RS_RATE(&ni->ni_rates, nrate) / 2 : 0); + + ni->ni_txrate = nrate; + + if (od == NULL) { + onoe_data_alloc(ni); + } else { + od->od_tx_ok = 0; + od->od_tx_err = 0; + od->od_tx_retr = 0; + od->od_tx_upper = 0; + } +} + +/* + * Set the starting transmit rate for a node. + */ +static void +onoe_start(struct onoe_softc *osc, struct ieee80211_node *ni) +{ +#define RATE(_ix) IEEE80211_RS_RATE(&ni->ni_rates, (_ix)) + struct ieee80211com *ic = osc->ic; + int srate; + + KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); + if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { + /* + * For adhoc or ibss mode, start from the lowest rate. + */ + if (ic->ic_opmode == IEEE80211_M_AHDEMO || + ic->ic_opmode == IEEE80211_M_IBSS) { + onoe_update(osc, ni, 0); + return; + } + + /* + * No fixed rate is requested. For 11b start with + * the highest negotiated rate; otherwise, for 11g + * and 11a, we start "in the middle" at 24Mb or 36Mb. + */ + srate = ni->ni_rates.rs_nrates - 1; + if (ic->ic_curmode != IEEE80211_MODE_11B) { + /* + * Scan the negotiated rate set to find the + * closest rate. + */ + /* NB: the rate set is assumed sorted */ + for (; srate >= 0 && RATE(srate) > 72; srate--) + ; + KASSERT(srate >= 0, ("bogus rate set")); + } + } else { + /* + * A fixed rate is to be used; ic_fixed_rate is an + * index into the supported rate set. Convert this + * to the index into the negotiated rate set for + * the node. We know the rate is there because the + * rate set is checked when the station associates. + */ + const struct ieee80211_rateset *rs = + &ic->ic_sup_rates[ic->ic_curmode]; + int r = IEEE80211_RS_RATE(rs, ic->ic_fixed_rate); + + /* NB: the rate set is assumed sorted */ + srate = ni->ni_rates.rs_nrates - 1; + for (; srate >= 0 && RATE(srate) != r; srate--) + ; + KASSERT(srate >= 0, + ("fixed rate %d not in rate set", ic->ic_fixed_rate)); + } + onoe_update(osc, ni, srate); +#undef RATE +} + +static void +onoe_rate_cb(void *arg, struct ieee80211_node *ni) +{ + onoe_update(arg, ni, 0); +} + +static void +onoe_newstate(void *arg, enum ieee80211_state state) +{ + struct onoe_softc *osc = arg; + struct ieee80211com *ic = osc->ic; + struct ieee80211_node *ni; + + if (state == IEEE80211_S_INIT) { + callout_stop(&osc->timer); + return; + } + + if (ic->ic_opmode == IEEE80211_M_STA) { + /* + * Reset local xmit state; this is really only + * meaningful when operating in station mode. + */ + ni = ic->ic_bss; + if (state == IEEE80211_S_RUN) + onoe_start(osc, ni); + else + onoe_update(osc, ni, 0); + } else { + /* + * When operating as a station the node table holds + * the AP's that were discovered during scanning. + * For any other operating mode we want to reset the + * tx rate state of each node. + */ + ieee80211_iterate_nodes(&ic->ic_sta, onoe_rate_cb, osc); + onoe_update(osc, ic->ic_bss, 0); + } + + if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE && + state == IEEE80211_S_RUN) { + int interval; + + /* + * Start the background rate control thread if we + * are not configured to use a fixed xmit rate. + */ + interval = osc->interval; + if (ic->ic_opmode == IEEE80211_M_STA) + interval /= 2; + callout_reset(&osc->timer, (interval * hz) / 1000, + onoe_tick, osc); + } +} + +static void +onoe_ratectl(void *arg, struct ieee80211_node *ni) +{ + struct onoe_softc *osc = arg; + struct onoe_data *od = ni->ni_rate_data; + struct ieee80211_rateset *rs = &ni->ni_rates; + int dir = 0, nrate, enough; + + if (od == NULL) { + /* We are no ready to go, set TX rate to lowest one */ + ni->ni_txrate = 0; + return; + } + + /* + * Rate control + * XXX: very primitive version. + */ + enough = (od->od_tx_ok + od->od_tx_err >= 10); + + /* no packet reached -> down */ + if (od->od_tx_err > 0 && od->od_tx_ok == 0) + dir = -1; + + /* all packets needs retry in average -> down */ + if (enough && od->od_tx_ok < od->od_tx_retr) + dir = -1; + + /* no error and less than rate_raise% of packets need retry -> up */ + if (enough && od->od_tx_err == 0 && + od->od_tx_retr < (od->od_tx_ok * osc->raise) / 100) + dir = 1; + + DPRINTF(osc, 10, "%6D: ok %d err %d retr %d upper %d dir %d\n", + ni->ni_macaddr, ":", + od->od_tx_ok, od->od_tx_err, od->od_tx_retr, + od->od_tx_upper, dir); + + nrate = ni->ni_txrate; + switch (dir) { + case 0: + if (enough && od->od_tx_upper > 0) + od->od_tx_upper--; + break; + case -1: + if (nrate > 0) + nrate--; + od->od_tx_upper = 0; + break; + case 1: + /* raise rate if we hit rate_raise_threshold */ + if (++od->od_tx_upper < osc->raise_threshold) + break; + od->od_tx_upper = 0; + if (nrate + 1 < rs->rs_nrates) + nrate++; + break; + } + + if (nrate != ni->ni_txrate) { + DPRINTF(osc, 5, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n", + __func__, + IEEE80211_RS_RATE(rs, ni->ni_txrate) / 2, + IEEE80211_RS_RATE(rs, nrate) / 2, + od->od_tx_ok, od->od_tx_err, od->od_tx_retr); + onoe_update(osc, ni, nrate); + } else if (enough) { + od->od_tx_ok = od->od_tx_err = od->od_tx_retr = 0; + } +} + +static void +onoe_tick(void *arg) +{ + struct onoe_softc *osc = arg; + struct ieee80211com *ic = osc->ic; + struct ifnet *ifp = &ic->ic_if; + int interval; + + lwkt_serialize_enter(ifp->if_serializer); + + if (ifp->if_flags & IFF_RUNNING) { + if (ic->ic_opmode == IEEE80211_M_STA) + onoe_ratectl(osc, ic->ic_bss); /* NB: no reference */ + else + ieee80211_iterate_nodes(&ic->ic_sta, onoe_ratectl, osc); + } + + interval = osc->interval; + if (ic->ic_opmode == IEEE80211_M_STA) + interval /= 2; + callout_reset(&osc->timer, (interval * hz) / 1000, onoe_tick, osc); + + lwkt_serialize_exit(ifp->if_serializer); +} + +static void +onoe_sysctl_attach(struct onoe_softc *osc) +{ + osc->interval = 1000; + osc->raise = 10; + osc->raise_threshold = 10; + osc->debug = 0; + + sysctl_ctx_init(&osc->sysctl_ctx); + osc->sysctl_oid = SYSCTL_ADD_NODE(&osc->sysctl_ctx, + SYSCTL_CHILDREN(osc->ic->ic_sysctl_oid), + OID_AUTO, "onoe_ratectl", CTLFLAG_RD, 0, ""); + if (osc->sysctl_oid == NULL) { + printf("wlan_ratectl_onoe: create sysctl tree failed\n"); + return; + } + + SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid), + OID_AUTO, "interval", CTLFLAG_RW, &osc->interval, 0, + "rate control: operation interval (ms)"); + + /* XXX bounds check values */ + SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid), + OID_AUTO, "raise", CTLFLAG_RW, &osc->raise, 0, + "rate control: " + "retry threshold to credit rate raise (%%)"); + + SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid), + OID_AUTO, "raise_threshold", CTLFLAG_RW, + &osc->raise_threshold, 0, + "rate control: # good periods before raising rate"); + + SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid), + OID_AUTO, "debug", CTLFLAG_RW, &osc->debug, 0, + "rate control: debug level"); +} + +static void * +onoe_attach(struct ieee80211com *ic) +{ + struct onoe_softc *osc; + + onoe_nrefs++; + + osc = malloc(sizeof(struct onoe_softc), M_DEVBUF, M_WAITOK | M_ZERO); + + osc->ic = ic; + callout_init(&osc->timer); + onoe_sysctl_attach(osc); + + onoe_newstate(osc, ic->ic_state); + + return osc; +} + +static void +_onoe_data_free(void *arg __unused, struct ieee80211_node *ni) +{ + onoe_data_free(ni); +} + +static void +onoe_detach(void *arg) +{ + struct onoe_softc *osc = arg; + struct ieee80211com *ic = osc->ic; + + onoe_newstate(osc, IEEE80211_S_INIT); + + ieee80211_iterate_nodes(&ic->ic_sta, _onoe_data_free, NULL); + ieee80211_iterate_nodes(&ic->ic_scan, _onoe_data_free, NULL); + + if (osc->sysctl_oid != NULL) + sysctl_ctx_free(&osc->sysctl_ctx); + free(osc, M_DEVBUF); + + onoe_nrefs--; +} + +static void +onoe_data_free(struct ieee80211_node *ni) +{ + if (ni->ni_rate_data != NULL) { + free(ni->ni_rate_data, M_ONOE_RATECTL_DATA); + ni->ni_rate_data = NULL; + } +} + +static void +onoe_data_alloc(struct ieee80211_node *ni) +{ + KKASSERT(ni->ni_rate_data == NULL); + ni->ni_rate_data = malloc(sizeof(struct onoe_data), + M_ONOE_RATECTL_DATA, M_NOWAIT | M_ZERO); +} + +static void +onoe_data_dup(const struct ieee80211_node *oni, struct ieee80211_node *nni) +{ + if (oni->ni_rate_data == NULL || nni->ni_rate_data == NULL) + return; + + bcopy(oni->ni_rate_data, nni->ni_rate_data, sizeof(struct onoe_data)); +} + +static int +onoe_modevent(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + ieee80211_ratectl_register(&onoe); + return 0; + case MOD_UNLOAD: + if (onoe_nrefs) { + printf("wlan_ratectl_onoe: still in use " + "(%u dynamic refs)\n", onoe_nrefs); + return EBUSY; + } + ieee80211_ratectl_unregister(&onoe); + return 0; + } + return EINVAL; +} + +static moduledata_t onoe_mod = { + "wlan_ratectl_onoe", + onoe_modevent, + 0 +}; +DECLARE_MODULE(wlan_ratectl_onoe, onoe_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(wlan_ratectl_onoe, 1); +MODULE_DEPEND(wlan_ratectl_onoe, wlan, 1, 1, 1); diff --git a/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h b/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h new file mode 100644 index 0000000000..70f56a3998 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.h,v 1.2 2004/12/31 22:41:45 sam Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/Attic/ieee80211_ratectl_onoe.h,v 1.1 2006/09/01 15:12:12 sephe Exp $ + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _IEEE80211_RATECTL_ONOE_H +#define _IEEE80211_RATECTL_ONOE_H + +struct onoe_softc { + struct ieee80211com *ic; + struct callout timer; /* periodic timer */ + + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_oid; + int interval; /* rate ctl interval (ms) */ + int raise; /* add credit threshold */ + int raise_threshold;/* rate ctl raise threshold */ + int debug; +}; + +struct onoe_data { + u_int od_tx_ok; /* tx ok pkt */ + u_int od_tx_err; /* tx !ok pkt */ + u_int od_tx_retr; /* tx retry count */ + int od_tx_upper; /* tx upper rate req cnt */ +}; + +#endif /* !_IEEE80211_RATECTL_ONOE_H */ -- 2.41.0