Implement a generic TX rate control algorithm framework in 802.11 layer.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 1 Sep 2006 15:12:12 +0000 (15:12 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 1 Sep 2006 15:12:12 +0000 (15:12 +0000)
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

24 files changed:
sbin/ifconfig/ifconfig.8
sbin/ifconfig/ifieee80211.c
sys/conf/files
sys/config/LINT
sys/i386/conf/LINT
sys/netproto/802_11/Makefile
sys/netproto/802_11/ieee80211.h
sys/netproto/802_11/ieee80211_ioctl.h
sys/netproto/802_11/ieee80211_node.h
sys/netproto/802_11/ieee80211_ratectl.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_var.h
sys/netproto/802_11/wlan/Makefile
sys/netproto/802_11/wlan/ieee80211.c
sys/netproto/802_11/wlan/ieee80211_ioctl.c
sys/netproto/802_11/wlan/ieee80211_node.c
sys/netproto/802_11/wlan/ieee80211_ratectl.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_ratectl_none.c [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/amrr/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/onoe/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h [new file with mode: 0644]

index 4b2e6b4..d32fc47 100644 (file)
@@ -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
index 7376a82..a8df137 100644 (file)
@@ -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 <netproto/802_11/ieee80211.h>
 #include <netproto/802_11/ieee80211_crypto.h>
 #include <netproto/802_11/ieee80211_ioctl.h>
+#include <netproto/802_11/ieee80211_ratectl.h>
 
 #include <ctype.h>
 #include <err.h>
@@ -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",
index 14aa737..466a615 100644 (file)
@@ -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
index b955c20..f473986 100644 (file)
@@ -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
index 18df91e..2e831bd 100644 (file)
@@ -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
index ad5fc7d..8999215 100644 (file)
@@ -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 <bsd.subdir.mk>
index b8f64a0..edb8600 100644 (file)
@@ -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
index e5e4cb5..2ba8cf1 100644 (file)
@@ -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.
index bd058f0..b95103d 100644 (file)
@@ -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 (file)
index 0000000..9991c50
--- /dev/null
@@ -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 <sepherosa@gmail.com>
+ * 
+ * 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 */
index 9777956..30ded2d 100644 (file)
@@ -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 <netproto/802_11/ieee80211_ioctl.h>   /* for ieee80211_stats */
 #include <netproto/802_11/ieee80211_node.h>
 #include <netproto/802_11/ieee80211_proto.h>
+#include <netproto/802_11/ieee80211_ratectl.h>
 
 #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 */
 };
index 5d1c628..37a39b9 100644 (file)
@@ -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
index 6b8611d..00564df 100644 (file)
@@ -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);
index dcb0ef9..a221285 100644 (file)
@@ -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;
index 44813c2..44a372e 100644 (file)
@@ -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 <sys/param.h>
@@ -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 : "<gone>");
 
+       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 (file)
index 0000000..662fbdc
--- /dev/null
@@ -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 <sepherosa@gmail.com>
+ * 
+ * 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 <sys/param.h>
+#include <sys/kernel.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#include <netproto/802_11/ieee80211_var.h>
+
+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 (file)
index 0000000..cf6ea70
--- /dev/null
@@ -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 <sepherosa@gmail.com>
+ * 
+ * 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 <sys/param.h>
+#include <sys/kernel.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#include <netproto/802_11/ieee80211_var.h>
+
+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 (file)
index 0000000..7a5f2c8
--- /dev/null
@@ -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 <bsd.subdir.mk>
diff --git a/sys/netproto/802_11/wlan_ratectl/amrr/Makefile b/sys/netproto/802_11/wlan_ratectl/amrr/Makefile
new file mode 100644 (file)
index 0000000..2bb12af
--- /dev/null
@@ -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 <bsd.kmod.mk>
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 (file)
index 0000000..393fa66
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/serialize.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h>
+
+#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 (file)
index 0000000..7f6b9df
--- /dev/null
@@ -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 (file)
index 0000000..7496884
--- /dev/null
@@ -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 <bsd.kmod.mk>
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 (file)
index 0000000..fe26761
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/serialize.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h>
+
+#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 (file)
index 0000000..70f56a3
--- /dev/null
@@ -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 */