From 1e49c82c0ee6b6537e8c380ed41a7d31f0e48f5f Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 1 Apr 2007 13:59:41 +0000 Subject: [PATCH] - Define 802.11 modulation types as 'enum ieee80211_modtype'. - Expose ieee80211_rate2modtype() for pubic use. - Add definition for DIFS, slot time and contention window. - Add addition field in TX rate control state structure, so drivers can give hints to TX rate control algorithms about their capabilities. - Add Sample TX rate control support: http://www.pdos.lcs.mit.edu/papers/jbicket-ms.pdf It is factored out and adapted from the one in ath(4). - In ieee80211_ratectl.h, expose only IEEE80211_RATECTL_{ONOE,AMRR,SAMPLE} for user space program. - Teach ifconfig(8) to show and set Sample TX rate control algorithm. - Fix a node leakage on rt2560_tx_mgt() error handling path. - Support Onoe and Sample TX rate control algorithm in 2560 part of ral(4), and use Sample TX rate control algorithm as the default TX rate control algorithm. [*] - Make ral(4) depend on wlan_ratectl_{onoe,sample}. - Hook Sample TX rate control algorithm into GENERIC and LINT. # [*] # If Sample TX rate control algorithm is used, I get almost 100~200% # UDP_STREAM netperf TX performance boost than the original TX rate # control algorithm in open/noisy enviroments, and +200~500Kbits/s # UDP_STREAM netperf TX performance boost under good conditions. --- sbin/ifconfig/ifieee80211.c | 7 +- sys/conf/files | 3 +- sys/config/GENERIC | 5 +- sys/config/LINT | 5 +- sys/dev/netif/ral/Makefile | 4 +- sys/dev/netif/ral/if_ral_pci.c | 4 +- sys/dev/netif/ral/rt2560.c | 176 ++-- sys/dev/netif/ral/rt2560var.h | 10 +- sys/netproto/802_11/_ieee80211.h | 9 +- sys/netproto/802_11/ieee80211.h | 27 +- sys/netproto/802_11/ieee80211_ratectl.h | 18 +- sys/netproto/802_11/ieee80211_var.h | 3 +- sys/netproto/802_11/wlan/ieee80211.c | 15 +- sys/netproto/802_11/wlan/ieee80211_output.c | 27 +- sys/netproto/802_11/wlan/ieee80211_ratectl.c | 5 +- sys/netproto/802_11/wlan_ratectl/Makefile | 4 +- sys/netproto/802_11/wlan_ratectl/sample/Makefile | 7 + .../wlan_ratectl/sample/ieee80211_ratectl_sample.c | 884 +++++++++++++++++++++ .../wlan_ratectl/sample/ieee80211_ratectl_sample.h | 92 +++ 19 files changed, 1144 insertions(+), 161 deletions(-) create mode 100644 sys/netproto/802_11/wlan_ratectl/sample/Makefile create mode 100644 sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c create mode 100644 sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.h diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c index aeecd21df6..917ed63257 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.10 2006/08/10 06:09:23 sam Exp $ - * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.17 2006/12/08 15:25:07 sephe Exp $ + * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.18 2007/04/01 13:59:40 sephe Exp $ */ /*- @@ -680,6 +680,8 @@ set80211ratectl(const char *val, int d, int s, const struct afswtch *rafp) ratectl = IEEE80211_RATECTL_ONOE; else if (strcmp("amrr", val) == 0) ratectl = IEEE80211_RATECTL_AMRR; + else if (strcmp("sample", val) == 0) + ratectl = IEEE80211_RATECTL_SAMPLE; else errx(1, "unknown ratectl"); @@ -1501,6 +1503,9 @@ ieee80211_status(int s) case IEEE80211_RATECTL_AMRR: printf("\tratectl: amrr"); break; + case IEEE80211_RATECTL_SAMPLE: + printf("\tratectl: sample"); + break; default: if (verbose) printf("\tratectl: none"); diff --git a/sys/conf/files b/sys/conf/files index 6222e40629..a55d4819ad 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.152 2007/02/11 02:51:28 swildner Exp $ +# $DragonFly: src/sys/conf/files,v 1.153 2007/04/01 13:59:41 sephe Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -755,6 +755,7 @@ 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/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c optional wlan_ratectl_sample 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/GENERIC b/sys/config/GENERIC index fed247c609..65e368b5d9 100644 --- a/sys/config/GENERIC +++ b/sys/config/GENERIC @@ -4,7 +4,7 @@ # Check the LINT configuration file in sys/config, for an # exhaustive list of options. # -# $DragonFly: src/sys/config/GENERIC,v 1.48 2007/01/19 08:23:42 dillon Exp $ +# $DragonFly: src/sys/config/GENERIC,v 1.49 2007/04/01 13:59:41 sephe Exp $ platform pc32 machine i386 @@ -228,6 +228,7 @@ device wlan_wep # 802.11 WEP support # 802.11 TX rate control algorithms #device wlan_ratectl_amrr # AMRR device wlan_ratectl_onoe # Onoe +device wlan_ratectl_sample # Sample # Aironet 4500/4800 802.11 wireless NICs. Note: the declaration below will # work for PCMCIA and PCI cards, as well as ISA cards set to ISA PnP @@ -237,6 +238,8 @@ device wlan_ratectl_onoe # Onoe device an device awi # PRISM I IEEE 802.11b wireless NIC device ral # Ralink Technology 802.11 wireless NIC + # Requires wlan_ratectl_onoe and + # wlan_ratectl_sample device rtw # RealTek 802.11 wireless NIC # Requires wlan_ratectl_onoe and wlan_wep # WaveLAN/IEEE 802.11 wireless NICs. Note: the WaveLAN/IEEE really diff --git a/sys/config/LINT b/sys/config/LINT index bdcf52de6c..86e23aa1ad 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.108 2007/03/17 21:24:11 swildner Exp $ +# $DragonFly: src/sys/config/LINT,v 1.109 2007/04/01 13:59:41 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 @@ -1426,6 +1426,7 @@ 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 +device wlan_ratectl_sample # 802.11 Sample TX rate control algorithm options WLCACHE # enables the signal-strength cache options WLDEBUG # enables verbose debugging output device awi # AMD PCnetMobile @@ -1442,6 +1443,8 @@ device wl0 at isa? port 0x300 # T1 speed ISA/radio lan device xe # Xircom PCMCIA device ray # Raytheon Raylink/Webgear Aviator device ral # Ralink Technology 802.11 wireless NIC + # Requires wlan_ratectl_onoe and + # wlan_ratectl_sample device oltr0 at isa? diff --git a/sys/dev/netif/ral/Makefile b/sys/dev/netif/ral/Makefile index 7635f65d34..d556c26aab 100644 --- a/sys/dev/netif/ral/Makefile +++ b/sys/dev/netif/ral/Makefile @@ -1,7 +1,9 @@ -# $DragonFly: src/sys/dev/netif/ral/Makefile,v 1.1 2006/05/20 11:13:09 sephe Exp $ +# $DragonFly: src/sys/dev/netif/ral/Makefile,v 1.2 2007/04/01 13:59:40 sephe Exp $ KMOD = if_ral SRCS = if_ral_pci.c if_ralrate.c rt2560.c rt2661.c SRCS += device_if.h bus_if.h pci_if.h +KMODDEPS= wlan wlan_ratectl_onoe wlan_ratectl_sample + .include diff --git a/sys/dev/netif/ral/if_ral_pci.c b/sys/dev/netif/ral/if_ral_pci.c index 0ad9d07fa1..5d6a482c08 100644 --- a/sys/dev/netif/ral/if_ral_pci.c +++ b/sys/dev/netif/ral/if_ral_pci.c @@ -15,7 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD: src/sys/dev/ral/if_ral_pci.c,v 1.4 2006/03/05 23:27:51 silby Exp $ - * $DragonFly: src/sys/dev/netif/ral/if_ral_pci.c,v 1.3 2006/10/25 22:55:58 dillon Exp $ + * $DragonFly: src/sys/dev/netif/ral/if_ral_pci.c,v 1.4 2007/04/01 13:59:40 sephe Exp $ */ /* @@ -138,6 +138,8 @@ DRIVER_MODULE(ral, pci, ral_pci_driver, ral_devclass, 0, 0); DRIVER_MODULE(ral, cardbus, ral_pci_driver, ral_devclass, 0, 0); MODULE_DEPEND(ral, wlan, 1, 1, 1); +MODULE_DEPEND(ral, wlan_ratectl_onoe, 1, 1, 1); +MODULE_DEPEND(ral, wlan_ratectl_sample, 1, 1, 1); MODULE_DEPEND(ral, pci, 1, 1, 1); MODULE_DEPEND(ral, cardbus, 1, 1, 1); diff --git a/sys/dev/netif/ral/rt2560.c b/sys/dev/netif/ral/rt2560.c index 1f621e6b02..c95fdb663a 100644 --- a/sys/dev/netif/ral/rt2560.c +++ b/sys/dev/netif/ral/rt2560.c @@ -15,7 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD: src/sys/dev/ral/rt2560.c,v 1.3 2006/03/21 21:15:43 damien Exp $ - * $DragonFly: src/sys/dev/netif/ral/rt2560.c,v 1.12 2007/03/30 11:39:33 sephe Exp $ + * $DragonFly: src/sys/dev/netif/ral/rt2560.c,v 1.13 2007/04/01 13:59:40 sephe Exp $ */ /* @@ -47,7 +47,6 @@ #include #include -#include #include #include @@ -80,12 +79,8 @@ static void rt2560_reset_rx_ring(struct rt2560_softc *, struct rt2560_rx_ring *); static void rt2560_free_rx_ring(struct rt2560_softc *, struct rt2560_rx_ring *); -static struct ieee80211_node *rt2560_node_alloc( - struct ieee80211_node_table *); static int rt2560_media_change(struct ifnet *); static void rt2560_next_scan(void *); -static void rt2560_iter_func(void *, struct ieee80211_node *); -static void rt2560_update_rssadapt(void *); static int rt2560_newstate(struct ieee80211com *, enum ieee80211_state, int); static uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); @@ -193,7 +188,6 @@ rt2560_attach(device_t dev, int id) int error, i; callout_init(&sc->scan_ch); - callout_init(&sc->rssadapt_ch); sc->sc_irq_rid = 0; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irq_rid, @@ -274,6 +268,10 @@ rt2560_attach(device_t dev, int id) ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ ic->ic_state = IEEE80211_S_INIT; + ic->ic_ratectl.rc_st_ratectl_cap = IEEE80211_RATECTL_CAP_ONOE | + IEEE80211_RATECTL_CAP_SAMPLE; + ic->ic_ratectl.rc_st_ratectl = IEEE80211_RATECTL_SAMPLE; + /* set device capabilities */ ic->ic_caps = IEEE80211_C_IBSS | /* IBSS mode supported */ @@ -323,7 +321,6 @@ rt2560_attach(device_t dev, int id) sc->sc_sifs = IEEE80211_DUR_SIFS; /* Default SIFS */ ieee80211_ifattach(ic); - ic->ic_node_alloc = rt2560_node_alloc; ic->ic_updateslot = rt2560_update_slot; ic->ic_reset = rt2560_reset; /* enable s/w bmiss handling in sta mode */ @@ -391,7 +388,6 @@ rt2560_detach(void *xsc) lwkt_serialize_enter(ifp->if_serializer); callout_stop(&sc->scan_ch); - callout_stop(&sc->rssadapt_ch); rt2560_stop(sc); bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih); @@ -774,17 +770,6 @@ rt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) } } -static struct ieee80211_node * -rt2560_node_alloc(struct ieee80211_node_table *nt) -{ - struct rt2560_node *rn; - - rn = kmalloc(sizeof(struct rt2560_node), M_80211_NODE, - M_NOWAIT | M_ZERO); - - return (rn != NULL) ? &rn->ni : NULL; -} - static int rt2560_media_change(struct ifnet *ifp) { @@ -817,36 +802,6 @@ rt2560_next_scan(void *arg) lwkt_serialize_exit(ifp->if_serializer); } -/* - * This function is called for each node present in the node station table. - */ -static void -rt2560_iter_func(void *arg, struct ieee80211_node *ni) -{ - struct rt2560_node *rn = (struct rt2560_node *)ni; - - ral_rssadapt_updatestats(&rn->rssadapt); -} - -/* - * This function is called periodically (every 100ms) in RUN state to update - * the rate adaptation statistics. - */ -static void -rt2560_update_rssadapt(void *arg) -{ - struct rt2560_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; - - lwkt_serialize_enter(ifp->if_serializer); - - ieee80211_iterate_nodes(&ic->ic_sta, rt2560_iter_func, arg); - callout_reset(&sc->rssadapt_ch, hz / 10, rt2560_update_rssadapt, sc); - - lwkt_serialize_exit(ifp->if_serializer); -} - static int rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { @@ -858,11 +813,10 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) ostate = ic->ic_state; callout_stop(&sc->scan_ch); + ieee80211_ratectl_newstate(ic, nstate); switch (nstate) { case IEEE80211_S_INIT: - callout_stop(&sc->rssadapt_ch); - if (ostate == IEEE80211_S_RUN) { /* abort TSF synchronization */ RAL_WRITE(sc, RT2560_CSR14, 0); @@ -916,12 +870,8 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) /* turn assocation led on */ rt2560_update_led(sc, 1, 0); - if (ic->ic_opmode != IEEE80211_M_MONITOR) { - callout_reset(&sc->rssadapt_ch, hz / 10, - rt2560_update_rssadapt, sc); - + if (ic->ic_opmode != IEEE80211_M_MONITOR) rt2560_enable_tsf_sync(sc); - } break; } @@ -1038,65 +988,84 @@ rt2560_tx_intr(struct rt2560_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = ic->ic_ifp; - struct rt2560_tx_desc *desc; - struct rt2560_tx_data *data; - struct rt2560_node *rn; bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, BUS_DMASYNC_POSTREAD); for (;;) { + struct rt2560_tx_desc *desc; + struct rt2560_tx_data *data; + struct ieee80211_node *ni; + int rateidx, data_retries, failed; + struct mbuf *m; + uint32_t flags; + desc = &sc->txq.desc[sc->txq.next]; data = &sc->txq.data[sc->txq.next]; - if ((le32toh(desc->flags) & RT2560_TX_BUSY) || - (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY) || - !(le32toh(desc->flags) & RT2560_TX_VALID)) + flags = le32toh(desc->flags); + + if ((flags & RT2560_TX_BUSY) || + (flags & RT2560_TX_CIPHER_BUSY) || + !(flags & RT2560_TX_VALID)) break; - rn = (struct rt2560_node *)data->ni; + rateidx = data->rateidx; + ni = data->ni; + m = data->m; - switch (le32toh(desc->flags) & RT2560_TX_RESULT_MASK) { + data->ni = NULL; + data->m = NULL; + + failed = 0; + switch (flags & RT2560_TX_RESULT_MASK) { case RT2560_TX_SUCCESS: DPRINTFN(10, ("data frame sent successfully\n")); - if (data->id.id_node != NULL) { - ral_rssadapt_raise_rate(ic, &rn->rssadapt, - &data->id); - } ifp->if_opackets++; + data_retries = 0; break; case RT2560_TX_SUCCESS_RETRY: + data_retries = (flags >> 5) & 0x7; DPRINTFN(9, ("data frame sent after %u retries\n", - (le32toh(desc->flags) >> 5) & 0x7)); + data_retries)); ifp->if_opackets++; break; case RT2560_TX_FAIL_RETRY: DPRINTFN(9, ("sending data frame failed (too much " "retries)\n")); - if (data->id.id_node != NULL) { - ral_rssadapt_lower_rate(ic, data->ni, - &rn->rssadapt, &data->id); - } ifp->if_oerrors++; + data_retries = 7; + failed = 1; break; case RT2560_TX_FAIL_INVALID: case RT2560_TX_FAIL_OTHER: default: + data_retries = 7; + failed = 1; device_printf(sc->sc_dev, "sending data frame failed " - "0x%08x\n", le32toh(desc->flags)); + "0x%08x\n", flags); ifp->if_oerrors++; + break; } bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->txq.data_dmat, data->map); - m_freem(data->m); - data->m = NULL; - ieee80211_free_node(data->ni); - data->ni = NULL; + + if (rateidx >= 0) { + struct ieee80211_ratectl_res res; + + res.rc_res_tries = data_retries + 1; + res.rc_res_rateidx = rateidx; + ieee80211_ratectl_tx_complete(ni, m->m_pkthdr.len, + &res, 1, data_retries, 0, failed); + } + + m_freem(m); + ieee80211_free_node(ni); /* descriptor is no longer valid */ desc->flags &= ~htole32(RT2560_TX_VALID); @@ -1161,8 +1130,8 @@ rt2560_prio_intr(struct rt2560_softc *sc) bus_dmamap_unload(sc->prioq.data_dmat, data->map); m_freem(data->m); data->m = NULL; - ieee80211_free_node(data->ni); - data->ni = NULL; + + KASSERT(data->ni == NULL, ("mgmt node is not empty\n")); /* descriptor is no longer valid */ desc->flags &= ~htole32(RT2560_TX_VALID); @@ -1195,7 +1164,6 @@ rt2560_decryption_intr(struct rt2560_softc *sc) bus_addr_t physaddr; struct ieee80211_frame *wh; struct ieee80211_node *ni; - struct rt2560_node *rn; struct mbuf *mnew, *m; int hw, error; @@ -1301,11 +1269,6 @@ rt2560_decryption_intr(struct rt2560_softc *sc) /* send the frame to the 802.11 layer */ ieee80211_input(ic, m, ni, RT2560_RSSI(sc, desc->rssi), 0); - /* give rssi to the rate adatation algorithm */ - rn = (struct rt2560_node *)ni; - ral_rssadapt_input(ic, ni, &rn->rssadapt, - RT2560_RSSI(sc, desc->rssi)); - /* node is no longer needed */ ieee80211_free_node(ni); @@ -1651,6 +1614,7 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, if (error != 0) { device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", error); + ieee80211_free_node(ni); m_freem(m0); return error; } @@ -1668,7 +1632,7 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, } data->m = m0; - data->ni = ni; + data->ni = NULL; wh = mtod(m0, struct ieee80211_frame *); @@ -1701,6 +1665,8 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); + ieee80211_free_node(ni); + return 0; } @@ -1742,30 +1708,15 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, struct ieee80211com *ic = &sc->sc_ic; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; - struct rt2560_node *rn; - struct ieee80211_rateset *rs; struct ieee80211_frame *wh; struct ieee80211_key *k; struct mbuf *mnew; bus_addr_t paddr; uint16_t dur; uint32_t flags = 0; - int rate, error, ackrate; + int rate, error, ackrate, rateidx; wh = mtod(m0, struct ieee80211_frame *); - - if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { - rs = &ic->ic_sup_rates[ic->ic_curmode]; - rate = rs->rs_rates[ic->ic_fixed_rate]; - } else { - rs = &ni->ni_rates; - rn = (struct rt2560_node *)ni; - ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs, wh, - m0->m_pkthdr.len, NULL, 0); - rate = rs->rs_rates[ni->ni_txrate]; - } - rate &= IEEE80211_RATE_VAL; - if (wh->i_fc[1] & IEEE80211_FC1_WEP) { k = ieee80211_crypto_encap(ic, ni, m0); if (k == NULL) { @@ -1777,6 +1728,9 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, wh = mtod(m0, struct ieee80211_frame *); } + ieee80211_ratectl_findrate(ni, m0->m_pkthdr.len, &rateidx, 1); + rate = IEEE80211_RS_RATE(&ni->ni_rates, rateidx); + ackrate = ieee80211_ack_rate(ni, rate); /* @@ -1817,9 +1771,7 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, data->m = m; data->ni = ni; - - /* RTS frames are not taken into account for rssadapt */ - data->id.id_node = NULL; + data->rateidx = -1; /* don't count RTS */ rt2560_setup_tx_desc(sc, desc, RT2560_TX_ACK | RT2560_TX_MORE_FRAG, m->m_pkthdr.len, rtsrate, 1, paddr); @@ -1888,15 +1840,7 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, data->m = m0; data->ni = ni; - - /* remember link conditions for rate adaptation algorithm */ - if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { - data->id.id_len = m0->m_pkthdr.len; - data->id.id_rateidx = ni->ni_txrate; - data->id.id_node = ni; - data->id.id_rssi = ni->ni_rssi; - } else - data->id.id_node = NULL; + data->rateidx = rateidx; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2560_TX_ACK; diff --git a/sys/dev/netif/ral/rt2560var.h b/sys/dev/netif/ral/rt2560var.h index 5a86973ab3..3666dd8f89 100644 --- a/sys/dev/netif/ral/rt2560var.h +++ b/sys/dev/netif/ral/rt2560var.h @@ -15,7 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD: src/sys/dev/ral/rt2560var.h,v 1.1 2006/03/05 20:36:56 damien Exp $ - * $DragonFly: src/sys/dev/netif/ral/rt2560var.h,v 1.3 2007/03/30 11:39:33 sephe Exp $ + * $DragonFly: src/sys/dev/netif/ral/rt2560var.h,v 1.4 2007/04/01 13:59:40 sephe Exp $ */ struct rt2560_rx_radiotap_header { @@ -56,7 +56,7 @@ struct rt2560_tx_data { bus_dmamap_t map; struct mbuf *m; struct ieee80211_node *ni; - struct ral_rssdesc id; + int rateidx; }; struct rt2560_tx_ring { @@ -93,11 +93,6 @@ struct rt2560_rx_ring { int cur_decrypt; }; -struct rt2560_node { - struct ieee80211_node ni; - struct ral_rssadapt rssadapt; -}; - struct rt2560_softc { /* * NOTE: following four fields MUST be in the @@ -116,7 +111,6 @@ struct rt2560_softc { enum ieee80211_state, int); struct callout scan_ch; - struct callout rssadapt_ch; int sc_tx_timer; int sc_sifs; diff --git a/sys/netproto/802_11/_ieee80211.h b/sys/netproto/802_11/_ieee80211.h index 8d9e5e2a6a..ed77bee94f 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.2.2.1 2005/09/03 22:40:02 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/_ieee80211.h,v 1.1 2006/05/18 15:51:46 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/_ieee80211.h,v 1.2 2007/04/01 13:59:40 sephe Exp $ */ #ifndef _NET80211__IEEE80211_H_ #define _NET80211__IEEE80211_H_ @@ -63,6 +63,13 @@ enum ieee80211_opmode { IEEE80211_M_MONITOR = 8 /* Monitor mode */ }; +enum ieee80211_modtype { + IEEE80211_MODTYPE_DS = 0, /* DS/CCK modulation */ + IEEE80211_MODTYPE_PBCC = 1, /* PBCC modulation */ + IEEE80211_MODTYPE_OFDM = 2 /* OFDM modulation */ +}; +#define IEEE80211_MODTYPE_CCK IEEE80211_MODTYPE_DS + /* * 802.11g protection mode. */ diff --git a/sys/netproto/802_11/ieee80211.h b/sys/netproto/802_11/ieee80211.h index 53ebc399de..1d1a53dc84 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.2 2006/08/10 06:07:49 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/ieee80211.h,v 1.6 2007/03/30 11:39:34 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211.h,v 1.7 2007/04/01 13:59:40 sephe Exp $ */ #ifndef _NET80211_IEEE80211_H_ #define _NET80211_IEEE80211_H_ @@ -666,10 +666,29 @@ enum { #define IEEE80211_HWBMISS_MAX 255 /* - * IFS (microseconds) + * Contention window (slots). */ -#define IEEE80211_DUR_SIFS 10 /* DS/CCK/ERP-OFDM SIFS (11b/g) */ -#define IEEE80211_DUR_OFDM_SIFS 16 /* OFDM SIFS (11a) */ +#define IEEE80211_CW_MAX 1023 /* aCWmax */ +#define IEEE80211_CW_MIN_0 31 /* DS/CCK aCWmin, ERP aCWmin(0) */ +#define IEEE80211_CW_MIN_1 15 /* OFDM aCWmin, ERP aCWmin(1) */ + +/* + * SIFS (microseconds). + */ +#define IEEE80211_DUR_SIFS 10 /* DS/CCK/ERP SIFS */ +#define IEEE80211_DUR_OFDM_SIFS 16 /* OFDM SIFS */ + +/* + * Slot time (microseconds). + */ +#define IEEE80211_DUR_SLOT 20 /* DS/CCK slottime, ERP long slottime */ +#define IEEE80211_DUR_SHSLOT 9 /* ERP short slottime */ +#define IEEE80211_DUR_OFDM_SLOT 9 /* OFDM slottime */ + +/* + * DIFS (microseconds). + */ +#define IEEE80211_DUR_DIFS(sifs, slot) ((sifs) + 2 * (slot)) #define IEEE80211_MGT_SUBTYPE_NAMES { \ "assoc-req", "assoc-resp", \ diff --git a/sys/netproto/802_11/ieee80211_ratectl.h b/sys/netproto/802_11/ieee80211_ratectl.h index 40ff1c379d..ffce538b8b 100644 --- a/sys/netproto/802_11/ieee80211_ratectl.h +++ b/sys/netproto/802_11/ieee80211_ratectl.h @@ -31,17 +31,20 @@ * 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.4 2007/03/18 11:49:32 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211_ratectl.h,v 1.5 2007/04/01 13:59:40 sephe Exp $ */ #ifndef _NET80211_IEEE80211_RATECTL_H #define _NET80211_IEEE80211_RATECTL_H +#ifdef _KERNEL + struct ieee80211_ratectl_stats; struct ieee80211_ratectl_state { void *rc_st_ctx; void *rc_st_param; + uint32_t rc_st_flags; /* see IEEE80211_RATECTL_F_ */ u_int rc_st_ratectl; /* see IEEE80211_RATECTL_ */ uint32_t rc_st_ratectl_cap; /* see IEEE80211_RATECTL_CAP_ */ uint64_t rc_st_valid_stats; /* see IEEE80211_RATECTL_STATS_ */ @@ -51,6 +54,9 @@ struct ieee80211_ratectl_state { struct ieee80211_ratectl_stats *); }; +#define IEEE80211_RATECTL_F_RSDESC 0x1 /* Rate set must be descendant. */ +#define IEEE80211_RATECTL_F_MRR 0x2 /* Support multi-rate-retry. */ + struct ieee80211_ratectl_res { int rc_res_rateidx; int rc_res_tries; @@ -94,10 +100,15 @@ struct ieee80211_ratectl { int[], int); }; +#endif /* _KERNEL */ + #define IEEE80211_RATECTL_NONE 0 #define IEEE80211_RATECTL_ONOE 1 #define IEEE80211_RATECTL_AMRR 2 -#define IEEE80211_RATECTL_MAX 3 +#define IEEE80211_RATECTL_SAMPLE 3 +#define IEEE80211_RATECTL_MAX 4 + +#ifdef _KERNEL #define IEEE80211_RATECTL_CAP(v) (1 << (v)) @@ -107,6 +118,7 @@ struct ieee80211_ratectl { #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) +#define IEEE80211_RATECTL_CAP_SAMPLE _IEEE80211_RATECTL_CAP(SAMPLE) extern const struct ieee80211_ratectl ieee80211_ratectl_none; @@ -131,4 +143,6 @@ void ieee80211_ratectl_tx_complete(struct ieee80211_node *, int, void ieee80211_ratectl_newassoc(struct ieee80211_node *, int); int ieee80211_ratectl_findrate(struct ieee80211_node *, int, int[], int); +#endif /* _KERNEL */ + #endif /* !_NET80211_IEEE80211_RATECTL_H */ diff --git a/sys/netproto/802_11/ieee80211_var.h b/sys/netproto/802_11/ieee80211_var.h index f98c88d10e..96d7d285b7 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.14 2007/03/05 14:17:36 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/ieee80211_var.h,v 1.15 2007/04/01 13:59:40 sephe Exp $ */ #ifndef _NET80211_IEEE80211_VAR_H_ #define _NET80211_IEEE80211_VAR_H_ @@ -324,6 +324,7 @@ u_int ieee80211_ieee2mhz(u_int, u_int); int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *, struct ieee80211_channel *); +enum ieee80211_modtype ieee80211_rate2modtype(uint8_t); uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int); uint8_t *ieee80211_add_xrates(uint8_t *, const struct ieee80211_rateset *); diff --git a/sys/netproto/802_11/wlan/ieee80211.c b/sys/netproto/802_11/wlan/ieee80211.c index 8bb4baface..fe36847b84 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.13 2007/03/24 08:39:03 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211.c,v 1.14 2007/04/01 13:59:41 sephe Exp $ */ /* @@ -1083,3 +1083,16 @@ ieee80211_plcp2rate(uint8_t plcp, int ofdm) } return 0; } + +enum ieee80211_modtype +ieee80211_rate2modtype(uint8_t rate) +{ + rate &= IEEE80211_RATE_VAL; + + if (rate == 44) + return IEEE80211_MODTYPE_PBCC; + else if (rate == 22 || rate < 12) + return IEEE80211_MODTYPE_DS; + else + return IEEE80211_MODTYPE_OFDM; +} diff --git a/sys/netproto/802_11/wlan/ieee80211_output.c b/sys/netproto/802_11/wlan/ieee80211_output.c index 3c7c823904..d6c95a426f 100644 --- a/sys/netproto/802_11/wlan/ieee80211_output.c +++ b/sys/netproto/802_11/wlan/ieee80211_output.c @@ -30,7 +30,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.26.2.8 2006/09/02 15:06:04 sam Exp $ - * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_output.c,v 1.19 2007/03/30 11:39:34 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_output.c,v 1.20 2007/04/01 13:59:41 sephe Exp $ */ #include "opt_inet.h" @@ -1802,27 +1802,15 @@ ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, ic->ic_set_tim(ni, 1); } -#define IEEE80211_MODTYPE_CCK 0 -#define IEEE80211_MODTYPE_OFDM 1 -#define IEEE80211_MODTYPE_PBCC 2 - -static int -ieee80211_rate2modtype(uint8_t rate) -{ - if (rate == 44) - return IEEE80211_MODTYPE_PBCC; - else if (rate == 22 || rate < 12) - return IEEE80211_MODTYPE_CCK; - else - return IEEE80211_MODTYPE_OFDM; -} - uint8_t ieee80211_ack_rate(struct ieee80211_node *ni, uint8_t rate) { const struct ieee80211_rateset *rs = &ni->ni_rates; uint8_t ack_rate = 0; - int modtype, i; + enum ieee80211_modtype modtype; + int i; + + rate &= IEEE80211_RATE_VAL; modtype = ieee80211_rate2modtype(rate); @@ -1919,8 +1907,11 @@ ieee80211_txtime(struct ieee80211_node *ni, u_int len, uint8_t rs_rate, uint32_t flags) { struct ieee80211com *ic = ni->ni_ic; + enum ieee80211_modtype modtype; uint16_t txtime; - int rate, modtype; + int rate; + + rs_rate &= IEEE80211_RATE_VAL; rate = rs_rate * 500; /* ieee80211 rate -> kbps */ diff --git a/sys/netproto/802_11/wlan/ieee80211_ratectl.c b/sys/netproto/802_11/wlan/ieee80211_ratectl.c index 550e576687..20cc1dbc20 100644 --- a/sys/netproto/802_11/wlan/ieee80211_ratectl.c +++ b/sys/netproto/802_11/wlan/ieee80211_ratectl.c @@ -31,7 +31,7 @@ * 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.3 2007/03/19 13:38:43 sephe Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_ratectl.c,v 1.4 2007/04/01 13:59:41 sephe Exp $ */ #include @@ -49,7 +49,8 @@ static const struct ieee80211_ratectl *ratectls[IEEE80211_RATECTL_MAX] = { static const char *ratectl_modname[IEEE80211_RATECTL_MAX] = { [IEEE80211_RATECTL_ONOE] = "wlan_ratectl_onoe", - [IEEE80211_RATECTL_AMRR] = "wlan_ratectl_amrr" + [IEEE80211_RATECTL_AMRR] = "wlan_ratectl_amrr", + [IEEE80211_RATECTL_SAMPLE] = "wlan_ratectl_sample" }; void diff --git a/sys/netproto/802_11/wlan_ratectl/Makefile b/sys/netproto/802_11/wlan_ratectl/Makefile index 01bc9dc1ef..5637a653cf 100644 --- a/sys/netproto/802_11/wlan_ratectl/Makefile +++ b/sys/netproto/802_11/wlan_ratectl/Makefile @@ -1,5 +1,5 @@ -# $DragonFly: src/sys/netproto/802_11/wlan_ratectl/Makefile,v 1.1 2006/09/01 17:12:11 sephe Exp $ +# $DragonFly: src/sys/netproto/802_11/wlan_ratectl/Makefile,v 1.2 2007/04/01 13:59:41 sephe Exp $ -SUBDIR= onoe amrr +SUBDIR= onoe amrr sample .include diff --git a/sys/netproto/802_11/wlan_ratectl/sample/Makefile b/sys/netproto/802_11/wlan_ratectl/sample/Makefile new file mode 100644 index 0000000000..7e7dc62e91 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/sample/Makefile @@ -0,0 +1,7 @@ +# $DragonFly: src/sys/netproto/802_11/wlan_ratectl/sample/Makefile,v 1.1 2007/04/01 13:59:41 sephe Exp $ + +KMOD = wlan_ratectl_sample +SRCS = ieee80211_ratectl_sample.c +KMODDEPS= wlan + +.include diff --git a/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c b/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c new file mode 100644 index 0000000000..dde655d301 --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c @@ -0,0 +1,884 @@ +/* + * Copyright (c) 2005 John Bicket + * 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/sample/sample.c,v 1.8.2.3 2006/03/14 23:22:27 sam Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c,v 1.1 2007/04/01 13:59:41 sephe Exp $ + */ + +/* + * John Bicket's SampleRate control algorithm. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define SAMPLE_DEBUG + +#ifdef SAMPLE_DEBUG +#define DPRINTF(ssc, lv, fmt, ...) do { \ + if (ssc->debug >= lv) \ + kprintf(fmt, __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(ssc, lv, fmt, ...) +#endif + +/* + * This file is an implementation of the SampleRate algorithm + * in "Bit-rate Selection in Wireless Networks" + * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) + * + * SampleRate chooses the bit-rate it predicts will provide the most + * throughput based on estimates of the expected per-packet + * transmission time for each bit-rate. SampleRate periodically sends + * packets at bit-rates other than the current one to estimate when + * another bit-rate will provide better performance. SampleRate + * switches to another bit-rate when its estimated per-packet + * transmission time becomes smaller than the current bit-rate's. + * SampleRate reduces the number of bit-rates it must sample by + * eliminating those that could not perform better than the one + * currently being used. SampleRate also stops probing at a bit-rate + * if it experiences several successive losses. + * + * The difference between the algorithm in the thesis and the one in this + * file is that the one in this file uses a ewma instead of a window. + * + * Also, this implementation tracks the average transmission time for + * a few different packet sizes independently for each link. + */ + +#define STALE_FAILURE_TIMEOUT_MS 10000 +#define MIN_SWITCH_MS 1000 + +static void *sample_attach(struct ieee80211com *); +static void sample_detach(void *); +static void sample_data_alloc(struct ieee80211_node *); +static void sample_data_free(struct ieee80211_node *); +static void sample_data_dup(const struct ieee80211_node *, + struct ieee80211_node *); +static void sample_newstate(void *, enum ieee80211_state); +static void sample_tx_complete(void *, struct ieee80211_node *, int, + const struct ieee80211_ratectl_res[], + int, int, int, int); +static void sample_newassoc(void *, struct ieee80211_node *, int); +static int sample_findrate(void *, struct ieee80211_node *, int, + int[], int); + +static void sample_sysctl_attach(struct sample_softc *); +static void sample_start(struct sample_softc *, struct ieee80211_node *); +static void sample_update_stats(struct sample_softc *, + struct ieee80211_node *, int, int, + const struct ieee80211_ratectl_res [], int, + int, int); + +static const struct ieee80211_ratectl sample = { + .rc_name = "sample", + .rc_ratectl = IEEE80211_RATECTL_SAMPLE, + .rc_attach = sample_attach, + .rc_detach = sample_detach, + .rc_data_alloc = sample_data_alloc, + .rc_data_free = sample_data_free, + .rc_data_dup = sample_data_dup, + .rc_newstate = sample_newstate, + .rc_tx_complete = sample_tx_complete, + .rc_newassoc = sample_newassoc, + .rc_findrate = sample_findrate +}; + +static u_int sample_nrefs; + +/* + * for now, we track performance for three different packet + * size buckets + */ +static int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600, 3000 }; + +MALLOC_DEFINE(M_SAMPLE_RATECTL_DATA, "sample_ratectl_data", + "sample rate control data"); + +static __inline int +size_to_bin(int size) +{ + int x; + + for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) { + if (size <= packet_size_bins[x]) + return x; + } + return NUM_PACKET_SIZE_BINS - 1; +} + +static __inline int +bin_to_size(int index) +{ + return packet_size_bins[index]; +} + +static __inline int +rate_to_ndx(struct ieee80211_node *ni, int rate) +{ + int x = 0; + + for (x = 0; x < ni->ni_rates.rs_nrates; x++) { + if (IEEE80211_RS_RATE(&ni->ni_rates, x) == rate) + return x; + } + return -1; +} + +static __inline int +unicast_pkt_time(struct sample_softc *ssc, struct ieee80211_node *ni, + int rate, int len, int data_tries, int rts_tries, + int *cw0) +{ + struct ieee80211com *ic = ssc->ic; + int sifs, difs, slot; + int ack_dur, data_dur, cw; + int tt = 0; + int i; + + ack_dur = ieee80211_txtime(ni, + sizeof(struct ieee80211_frame_ack) + IEEE80211_FCS_LEN, + ieee80211_ack_rate(ni, rate), ic->ic_flags); + data_dur = ieee80211_txtime(ni, len, rate, ic->ic_flags); + + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) { + cw = IEEE80211_CW_MIN_1; + sifs = IEEE80211_DUR_OFDM_SIFS; + slot = IEEE80211_DUR_OFDM_SLOT; + } else { + /* XXX should base on characteristic rate set */ + cw = IEEE80211_CW_MIN_0; + sifs = IEEE80211_DUR_SIFS; + slot = (ic->ic_flags & IEEE80211_F_SHSLOT) + ? IEEE80211_DUR_SHSLOT + : IEEE80211_DUR_SLOT; + } + if (cw0 != NULL && *cw0 != 0) + cw = *cw0; + difs = IEEE80211_DUR_DIFS(sifs, slot); + + if (rts_tries > 0 && (ic->ic_flags & IEEE80211_F_USEPROT) && + ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) { + if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { + uint8_t rts_rate; + int rts_dur, cts_dur; + + /* Assume RTS is sent at 2Mbits/s */ + rts_rate = 4; + + rts_dur = ieee80211_txtime(ni, + sizeof(struct ieee80211_frame_rts) + + IEEE80211_FCS_LEN, + rts_rate, ic->ic_flags); + cts_dur = ieee80211_txtime(ni, + sizeof(struct ieee80211_frame_cts) + + IEEE80211_FCS_LEN, + ieee80211_ack_rate(ni, rts_rate), + ic->ic_flags); + + tt += rts_tries * (rts_dur + sifs + cts_dur); + + /* + * Immediate data transmission does not perform backoff + * procedure. + * + * XXX not correct, if RTS retries (short retry count) + * reaches dot11ShortRetryLimit, which should be rare. + */ + tt += sifs; + --rts_tries; + } else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { + /* Assume CTS is sent at 2Mbits/s */ + tt += ieee80211_txtime(ni, + sizeof(struct ieee80211_frame_cts) + + IEEE80211_FCS_LEN, + 4, ic->ic_flags); + tt += sifs; + rts_tries = 0; + } + } else { + rts_tries = 0; + } + + tt += data_tries * (data_dur + sifs + ack_dur); + + /* Average time consumed by backoff procedure */ + for (i = 0; i < (data_tries + rts_tries); ++i) { + tt += difs + (slot * cw / 2); + cw = MIN(IEEE80211_CW_MAX + 1, (cw + 1) * 2) - 1; + } + if (cw0 != NULL) + *cw0 = cw; + return tt; +} + +/* + * returns the ndx with the lowest average_tx_time, + * or -1 if all the average_tx_times are 0. + */ +static __inline int +best_rate_ndx(struct ieee80211_node *ni, int size_bin, + int require_acked_before) +{ + int x, best_rate_ndx = 0, best_rate_tt = 0; + struct sample_data *sd = ni->ni_rate_data; + + for (x = 0; x < ni->ni_rates.rs_nrates; x++) { + int tt = sd->stats[size_bin][x].average_tx_time; + + if (tt <= 0 || + (require_acked_before && + !sd->stats[size_bin][x].packets_acked)) + continue; + + /* 9 megabits never works better than 12 */ + if (IEEE80211_RS_RATE(&ni->ni_rates, x) == 18) + continue; + + /* don't use a bit-rate that has been failing */ + if (sd->stats[size_bin][x].successive_failures > 3) + continue; + + if (!best_rate_tt || best_rate_tt > tt) { + best_rate_tt = tt; + best_rate_ndx = x; + } + } + return (best_rate_tt) ? best_rate_ndx : -1; +} + +/* + * pick a good "random" bit-rate to sample other than the current one + */ +static __inline int +pick_sample_ndx(struct ieee80211_node *ni, int size_bin) +{ + int x = 0; + int current_ndx = 0; + unsigned current_tt = 0; + struct sample_data *sd = ni->ni_rate_data; + + current_ndx = sd->current_rate[size_bin]; + if (current_ndx < 0) { + /* no successes yet, send at the lowest bit-rate */ + return 0; + } + + current_tt = sd->stats[size_bin][current_ndx].average_tx_time; + + for (x = 0; x < ni->ni_rates.rs_nrates; x++) { + int ndx = (sd->last_sample_ndx[size_bin] + 1 + x) % + ni->ni_rates.rs_nrates; + + /* don't sample the current bit-rate */ + if (ndx == current_ndx) + continue; + + /* this bit-rate is always worse than the current one */ + if (sd->stats[size_bin][ndx].perfect_tx_time > current_tt) + continue; + + /* rarely sample bit-rates that fail a lot */ + if (ticks - sd->stats[size_bin][ndx].last_tx < ((hz * STALE_FAILURE_TIMEOUT_MS) / 1000) && + sd->stats[size_bin][ndx].successive_failures > 3) + continue; + + /* + * don't sample more than 2 indexes higher + * for rates higher than 11 megabits + */ + if (IEEE80211_RS_RATE(&ni->ni_rates, ndx) > 22 && + ndx > current_ndx + 2) + continue; + + /* 9 megabits never works better than 12 */ + if (IEEE80211_RS_RATE(&ni->ni_rates, ndx) == 18) + continue; + + /* + * if we're using 11 megabits, only sample up to 12 megabits + */ + if (IEEE80211_RS_RATE(&ni->ni_rates, current_ndx) == 22 && + ndx > current_ndx + 1) + continue; + + sd->last_sample_ndx[size_bin] = ndx; + return ndx; + } + return current_ndx; +} + +static int +sample_findrate(void *arg, struct ieee80211_node *ni, int frame_len, + int rateidx[], int rateidx_len) +{ + struct sample_softc *ssc = arg; + struct sample_data *sd = ni->ni_rate_data; + struct ieee80211com *ic = ssc->ic; + struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl; + int ndx, size_bin, best_ndx, change_rates, ack_before, cur_ndx, i; + unsigned average_tx_time; + + for (i = 0; i < NUM_PACKET_SIZE_BINS; ++i) { + if (sd->current_rate[i] >= ni->ni_rates.rs_nrates) { + DPRINTF(ssc, 5, "%s: number of rates changed, " + "restart\n", __func__); + sample_start(ssc, ni); + break; + } + } + + KKASSERT(frame_len > 0); + size_bin = size_to_bin(frame_len); + + ack_before = (!(rc_st->rc_st_flags & IEEE80211_RATECTL_F_MRR) || + (ic->ic_flags & IEEE80211_F_USEPROT)); + best_ndx = best_rate_ndx(ni, size_bin, ack_before); + if (best_ndx >= 0) + average_tx_time = sd->stats[size_bin][best_ndx].average_tx_time; + else + average_tx_time = 0; + + if (sd->static_rate_ndx != -1) { + ndx = sd->static_rate_ndx; + } else { + if (sd->sample_tt[size_bin] < + average_tx_time * (sd->packets_since_sample[size_bin] * ssc->sample_rate / 100)) { + /* + * We want to limit the time measuring the + * performance of other bit-rates to sample_rate% + * of the total transmission time. + */ + ndx = pick_sample_ndx(ni, size_bin); + if (ndx != sd->current_rate[size_bin]) + sd->current_sample_ndx[size_bin] = ndx; + else + sd->current_sample_ndx[size_bin] = -1; + sd->packets_since_sample[size_bin] = 0; + } else { + change_rates = 0; + if (!sd->packets_sent[size_bin] || best_ndx == -1) { + /* no packet has been sent successfully yet */ + for (ndx = ni->ni_rates.rs_nrates - 1; ndx > 0; ndx--) { + /* + * pick the highest rate <= 36 Mbps + * that hasn't failed. + */ + if (IEEE80211_RS_RATE(&ni->ni_rates, ndx) <= 72 && + sd->stats[size_bin][ndx].successive_failures == 0) + break; + } + change_rates = 1; + best_ndx = ndx; + } else if (sd->packets_sent[size_bin] < 20) { + /* let the bit-rate switch quickly during the first few packets */ + change_rates = 1; + } else if (ticks - ((hz * MIN_SWITCH_MS) / 1000) > sd->ticks_since_switch[size_bin]) { + /* 2 seconds have gone by */ + change_rates = 1; + } else if (average_tx_time * 2 < sd->stats[size_bin][sd->current_rate[size_bin]].average_tx_time) { + /* the current bit-rate is twice as slow as the best one */ + change_rates = 1; + } + + sd->packets_since_sample[size_bin]++; + + if (change_rates) { + if (best_ndx != sd->current_rate[size_bin]) { + DPRINTF(ssc, 5, "%s: %6D size %d " + "switch rate " + "%d (%d/%d) -> %d (%d/%d) " + "after %d packets\n", + __func__, + ni->ni_macaddr, ":", + packet_size_bins[size_bin], + IEEE80211_RS_RATE(&ni->ni_rates, sd->current_rate[size_bin]), + sd->stats[size_bin][sd->current_rate[size_bin]].average_tx_time, + sd->stats[size_bin][sd->current_rate[size_bin]].perfect_tx_time, + IEEE80211_RS_RATE(&ni->ni_rates, best_ndx), + sd->stats[size_bin][best_ndx].average_tx_time, + sd->stats[size_bin][best_ndx].perfect_tx_time, + sd->packets_since_switch[size_bin]); + } + sd->packets_since_switch[size_bin] = 0; + sd->current_rate[size_bin] = best_ndx; + sd->ticks_since_switch[size_bin] = ticks; + } + ndx = sd->current_rate[size_bin]; + sd->packets_since_switch[size_bin]++; + if (size_bin == 0) { + /* + * set the visible txrate for this node + * to the rate of small packets + */ + ni->ni_txrate = ndx; + } + } + } + + KASSERT(ndx >= 0 && ndx < ni->ni_rates.rs_nrates, ("ndx is %d", ndx)); + + sd->packets_sent[size_bin]++; + + cur_ndx = sd->current_rate[size_bin]; + if (sd->stats[size_bin][cur_ndx].packets_acked == 0) + cur_ndx = 0; + + rateidx[0] = ndx; + i = 1; + if (rateidx_len > 2) { + if ((rc_st->rc_st_flags & IEEE80211_RATECTL_F_RSDESC) == 0 || + cur_ndx < ndx) + rateidx[i++] = cur_ndx; + else if (ndx > 0) + rateidx[i++] = ndx - 1; + } + if (i < rateidx_len && rateidx[i] != 0) + rateidx[i++] = 0; + return i; +} + +static void +sample_update_stats(struct sample_softc *ssc, struct ieee80211_node *ni, + int size, int size_bin, + const struct ieee80211_ratectl_res res[], int res_len, + int rts_tries, int is_fail) +{ + struct sample_data *sd = ni->ni_rate_data; + int tt, rate, i, ndx, cw = 0, data_tries; + + cw = 0; + ndx = res[0].rc_res_rateidx; + + rate = IEEE80211_RS_RATE(&ni->ni_rates, ndx); + tt = unicast_pkt_time(ssc, ni, rate, size, + res[0].rc_res_tries, rts_tries, &cw); + data_tries = res[0].rc_res_tries; + + for (i = 1; i < res_len; ++i) { + rate = IEEE80211_RS_RATE(&ni->ni_rates, res[i].rc_res_rateidx); + tt += unicast_pkt_time(ssc, ni, rate, size, + res[i].rc_res_tries, 0, &cw); + data_tries += res[i].rc_res_tries; + } + + if (sd->stats[size_bin][ndx].total_packets < (100 / (100 - ssc->smoothing_rate))) { + int avg_tx = sd->stats[size_bin][ndx].average_tx_time; + int packets = sd->stats[size_bin][ndx].total_packets; + + /* Average the first few packets. */ + sd->stats[size_bin][ndx].average_tx_time = + (tt + (avg_tx * packets)) / (packets + 1); + } else { + /* Use EWMA */ + sd->stats[size_bin][ndx].average_tx_time = + ((sd->stats[size_bin][ndx].average_tx_time * ssc->smoothing_rate) + + (tt * (100 - ssc->smoothing_rate))) / 100; + } + + if (is_fail) { + int y; + + sd->stats[size_bin][ndx].successive_failures++; + for (y = size_bin + 1; y < NUM_PACKET_SIZE_BINS; y++) { + /* + * also say larger packets failed since we + * assume if a small packet fails at a lower + * bit-rate then a larger one will also. + */ + sd->stats[y][ndx].successive_failures++; + sd->stats[y][ndx].last_tx = ticks; + sd->stats[y][ndx].tries += data_tries; + sd->stats[y][ndx].total_packets++; + } + } else { + sd->stats[size_bin][ndx].packets_acked++; + sd->stats[size_bin][ndx].successive_failures = 0; + } + sd->stats[size_bin][ndx].last_tx = ticks; + sd->stats[size_bin][ndx].tries += data_tries; + sd->stats[size_bin][ndx].total_packets++; + + if (ndx == sd->current_sample_ndx[size_bin]) { + DPRINTF(ssc, 10, "%s: %6D size %d sample rate %d " + "tries (d%d/r%d) tt %d avg_tt (%d/%d)%s\n", + __func__, ni->ni_macaddr, ":", + size, IEEE80211_RS_RATE(&ni->ni_rates, ndx), + data_tries, rts_tries, tt, + sd->stats[size_bin][ndx].average_tx_time, + sd->stats[size_bin][ndx].perfect_tx_time, + is_fail ? " fail" : ""); + sd->sample_tt[size_bin] = tt; + sd->current_sample_ndx[size_bin] = -1; + } +} + +static void +sample_tx_complete(void *arg, struct ieee80211_node *ni, int frame_len, + const struct ieee80211_ratectl_res res[], int res_len, + int data_retry, int rts_retry, int is_fail0) +{ + struct sample_softc *ssc = arg; + struct sample_data *sd = ni->ni_rate_data; + int i, size_bin, size; + + KKASSERT(frame_len > 0); + size_bin = size_to_bin(frame_len); + size = bin_to_size(size_bin); + + if (sd == NULL || !sd->started) { + DPRINTF(ssc, 10, "%s: %6D size %d retries (d%d/r%d) " + "no rates yet\n", __func__, + ni->ni_macaddr, ":", + size, data_retry, rts_retry); + return; + } + + for (i = 0; i < res_len; ++i) { + if (res[i].rc_res_rateidx >= ni->ni_rates.rs_nrates) { + DPRINTF(ssc, 5, "%s: number of rates changed, " + "restart\n", __func__); + sample_start(ssc, ni); + return; + } + } + + DPRINTF(ssc, 20, "%s: %6D size %d retries (d%d/r%d)\n", + __func__, ni->ni_macaddr, ":", + size, data_retry, rts_retry); + for (i = 0; i < res_len; ++i) { + int is_fail = is_fail0; + + if (i == 0 && (data_retry + 1) > res[0].rc_res_tries && + res[0].rc_res_rateidx == sd->current_sample_ndx[size_bin]) + is_fail = 1; + + sample_update_stats(ssc, ni, size, size_bin, + &res[i], res_len - i, + rts_retry + 1, is_fail); + } +} + +static void +sample_newassoc(void *arg, struct ieee80211_node *ni, int isnew) +{ + struct sample_softc *ssc = arg; + + DPRINTF(ssc, 5, "%s: %6D isnew %d\n", __func__, + ni->ni_macaddr, ":", isnew); + + if (isnew) + sample_start(ssc, ni); +} + +/* + * Initialize the tables for a node. + */ +static void +sample_start(struct sample_softc *ssc, struct ieee80211_node *ni) +{ +#define RATE(_ix) IEEE80211_RS_RATE(&ni->ni_rates, (_ix)) + struct ieee80211com *ic = ssc->ic; + struct sample_data *sd = ni->ni_rate_data; + int x, y, srate; + + if (sd == NULL) { + sample_data_alloc(ni); + + sd = ni->ni_rate_data; + if (sd == NULL) + return; + } + + sd->static_rate_ndx = -1; + if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { + /* + * 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. + */ + 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)); + sd->static_rate_ndx = srate; + } + +#ifdef SAMPLE_DEBUG + DPRINTF(ssc, 1, "%s: %6D size 1600 rate/tt", __func__, + ni->ni_macaddr, ":"); + for (x = 0; x < ni->ni_rates.rs_nrates; x++) { + DPRINTF(ssc, 1, " %d/%d", RATE(x), + unicast_pkt_time(ssc, ni, RATE(x), 1600, 1, 1, NULL)); + } + DPRINTF(ssc, 1, "%s\n", ""); +#endif + + /* Set the visible bit-rate to the lowest one available */ + ni->ni_txrate = 0; + + for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { + int size = bin_to_size(y); + int ndx = 0; + + sd->packets_sent[y] = 0; + sd->current_sample_ndx[y] = -1; + sd->last_sample_ndx[y] = 0; + + DPRINTF(ssc, 1, "%s: %6D size %d rate/tt", __func__, + ni->ni_macaddr, ":", size); + for (x = 0; x < ni->ni_rates.rs_nrates; x++) { + sd->stats[y][x].successive_failures = 0; + sd->stats[y][x].tries = 0; + sd->stats[y][x].total_packets = 0; + sd->stats[y][x].packets_acked = 0; + sd->stats[y][x].last_tx = 0; + + sd->stats[y][x].perfect_tx_time = + unicast_pkt_time(ssc, ni, RATE(x), size, + 1, 1, NULL); + + DPRINTF(ssc, 1, " %d/%d", RATE(x), + sd->stats[y][x].perfect_tx_time); + + sd->stats[y][x].average_tx_time = + sd->stats[y][x].perfect_tx_time; + } + DPRINTF(ssc, 1, "%s\n", ""); + + /* Set the initial rate */ + for (ndx = ni->ni_rates.rs_nrates - 1; ndx > 0; ndx--) { + if (RATE(ndx) <= 72) + break; + } + sd->current_rate[y] = ndx; + } + + DPRINTF(ssc, 1, "%s: %6D %d rates %d%sMbps (%dus)- %d%sMbps (%dus)\n", + __func__, ni->ni_macaddr, ":", + ni->ni_rates.rs_nrates, + RATE(0) / 2, RATE(0) % 2 ? ".5" : "", + sd->stats[1][0].perfect_tx_time, + RATE(ni->ni_rates.rs_nrates - 1) / 2, + RATE(ni->ni_rates.rs_nrates - 1) % 2 ? ".5" : "", + sd->stats[1][ni->ni_rates.rs_nrates - 1].perfect_tx_time); + + if (sd->static_rate_ndx != -1) + ni->ni_txrate = sd->static_rate_ndx; + else + ni->ni_txrate = sd->current_rate[0]; +#undef RATE + + sd->started = 1; +} + +static void +sample_rate_cb(void *arg, struct ieee80211_node *ni) +{ + sample_newassoc(arg, ni, 1); +} + +/* + * Reset the rate control state for each 802.11 state transition. + */ +static void +sample_newstate(void *arg, enum ieee80211_state state) +{ + struct sample_softc *ssc = arg; + + if (state == IEEE80211_S_RUN) { + struct ieee80211com *ic = ssc->ic; + + if (ic->ic_opmode != IEEE80211_M_STA) { + /* + * Sync rates for associated stations and neighbors. + */ + ieee80211_iterate_nodes(&ic->ic_sta, sample_rate_cb, + ssc); + } + sample_newassoc(ssc, ic->ic_bss, 1); + } +} + +static void +sample_sysctl_attach(struct sample_softc *ssc) +{ + ssc->smoothing_rate = 95; + ssc->sample_rate = 10; + ssc->debug = 0; + + sysctl_ctx_init(&ssc->sysctl_ctx); + ssc->sysctl_oid = SYSCTL_ADD_NODE(&ssc->sysctl_ctx, + SYSCTL_CHILDREN(ssc->ic->ic_sysctl_oid), + OID_AUTO, "sample_ratectl", CTLFLAG_RD, 0, ""); + if (ssc->sysctl_oid == NULL) { + kprintf("wlan_ratectl_sample: create sysctl tree failed\n"); + return; + } + + /* XXX bounds check [0..100] */ + SYSCTL_ADD_INT(&ssc->sysctl_ctx, SYSCTL_CHILDREN(ssc->sysctl_oid), + OID_AUTO, "smoothing_rate", CTLFLAG_RW, + &ssc->smoothing_rate, 0, + "rate control: " + "retry threshold to credit rate raise (%%)"); + + /* XXX bounds check [2..100] */ + SYSCTL_ADD_INT(&ssc->sysctl_ctx, SYSCTL_CHILDREN(ssc->sysctl_oid), + OID_AUTO, "sample_rate", CTLFLAG_RW, + &ssc->sample_rate, 0, + "rate control: " + "# good periods before raising rate"); + + SYSCTL_ADD_INT(&ssc->sysctl_ctx, SYSCTL_CHILDREN(ssc->sysctl_oid), + OID_AUTO, "debug", CTLFLAG_RW, &ssc->debug, 0, + "rate control: debug level"); +} + +static void * +sample_attach(struct ieee80211com *ic) +{ + struct sample_softc *ssc; + + sample_nrefs++; + + ssc = kmalloc(sizeof(struct sample_softc), M_DEVBUF, M_WAITOK | M_ZERO); + ssc->ic = ic; + sample_sysctl_attach(ssc); + + sample_newstate(ssc, ic->ic_state); + + return ssc; +} + +static void +_sample_data_free(void *arg __unused, struct ieee80211_node *ni) +{ + sample_data_free(ni); +} + +static void +sample_detach(void *arg) +{ + struct sample_softc *ssc = arg; + struct ieee80211com *ic = ssc->ic; + + sample_newstate(ssc, IEEE80211_S_INIT); + + ieee80211_iterate_nodes(&ic->ic_sta, _sample_data_free, NULL); + ieee80211_iterate_nodes(&ic->ic_scan, _sample_data_free, NULL); + + if (ssc->sysctl_oid != NULL) + sysctl_ctx_free(&ssc->sysctl_ctx); + kfree(ssc, M_DEVBUF); + + sample_nrefs--; +} + +static void +sample_data_alloc(struct ieee80211_node *ni) +{ + KKASSERT(ni->ni_rate_data == NULL); + ni->ni_rate_data = kmalloc(sizeof(struct sample_data), + M_SAMPLE_RATECTL_DATA, M_NOWAIT | M_ZERO); +} + +static void +sample_data_free(struct ieee80211_node *ni) +{ + if (ni->ni_rate_data != NULL) { + kfree(ni->ni_rate_data, M_SAMPLE_RATECTL_DATA); + ni->ni_rate_data = NULL; + } +} + +static void +sample_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 sample_data)); +} + +/* + * Module glue. + */ +static int +sample_modevent(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + ieee80211_ratectl_register(&sample); + return 0; + case MOD_UNLOAD: + if (sample_nrefs) { + kprintf("wlan_ratectl_sample: still in use " + "(%u dynamic refs)\n", sample_nrefs); + return EBUSY; + } + ieee80211_ratectl_unregister(&sample); + return 0; + } + return EINVAL; +} + +static moduledata_t sample_mod = { + "wlan_ratectl_sample", + sample_modevent, + 0 +}; +DECLARE_MODULE(wlan_ratectl_sample, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(wlan_ratectl_sample, 1); +MODULE_DEPEND(wlan_ratectl_sample, wlan, 1, 1, 1); diff --git a/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.h b/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.h new file mode 100644 index 0000000000..25518b5e8a --- /dev/null +++ b/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005 John Bicket + * 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/sample/sample.h,v 1.3.2.1 2006/02/24 19:51:11 sam Exp $ + * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.h,v 1.1 2007/04/01 13:59:41 sephe Exp $ + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _IEEE80211_RATECTL_SAMPLE_H +#define _IEEE80211_RATECYL_SAMPLE_H + +struct sample_softc { + struct ieee80211com *ic; + + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_oid; + + /* ewma percentage (out of 100) */ + int smoothing_rate; + + /* send a different bit-rate 1/X packets */ + int sample_rate; + + /* debug level */ + int debug; +}; + +struct rate_stats { + unsigned average_tx_time; + int successive_failures; + int tries; + int total_packets; + int packets_acked; + unsigned perfect_tx_time; /* transmit time for 0 retries */ + int last_tx; +}; + +#define NUM_PACKET_SIZE_BINS 3 + +struct sample_data { + int started; + int static_rate_ndx; + + struct rate_stats stats[NUM_PACKET_SIZE_BINS][IEEE80211_RATE_MAXSIZE]; + int last_sample_ndx[NUM_PACKET_SIZE_BINS]; + + int current_sample_ndx[NUM_PACKET_SIZE_BINS]; + int packets_sent[NUM_PACKET_SIZE_BINS]; + + int current_rate[NUM_PACKET_SIZE_BINS]; + int packets_since_switch[NUM_PACKET_SIZE_BINS]; + unsigned ticks_since_switch[NUM_PACKET_SIZE_BINS]; + + int packets_since_sample[NUM_PACKET_SIZE_BINS]; + unsigned sample_tt[NUM_PACKET_SIZE_BINS]; +}; + +#endif /* !_IEEE80211_RATECTL_SAMPLE_H */ -- 2.11.4.GIT