xref: /dflybsd-src/sys/netproto/802_11/wlan/ieee80211_rssadapt.c (revision a72c14d04185056737ff168f4b897cdd11e5243f)
14028af95SRui Paulo /*	$FreeBSD: head/sys/net80211/ieee80211_rssadapt.c 206358 2010-04-07 15:29:13Z rpaulo $	*/
232176cfdSRui Paulo /* $NetBSD: ieee80211_rssadapt.c,v 1.9 2005/02/26 22:45:09 perry Exp $ */
332176cfdSRui Paulo /*-
44028af95SRui Paulo  * Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
532176cfdSRui Paulo  * Copyright (c) 2003, 2004 David Young.  All rights reserved.
632176cfdSRui Paulo  *
732176cfdSRui Paulo  * Redistribution and use in source and binary forms, with or
832176cfdSRui Paulo  * without modification, are permitted provided that the following
932176cfdSRui Paulo  * conditions are met:
1032176cfdSRui Paulo  * 1. Redistributions of source code must retain the above copyright
1132176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer.
1232176cfdSRui Paulo  * 2. Redistributions in binary form must reproduce the above
1332176cfdSRui Paulo  *    copyright notice, this list of conditions and the following
1432176cfdSRui Paulo  *    disclaimer in the documentation and/or other materials provided
1532176cfdSRui Paulo  *    with the distribution.
1632176cfdSRui Paulo  * 3. The name of David Young may not be used to endorse or promote
1732176cfdSRui Paulo  *    products derived from this software without specific prior
1832176cfdSRui Paulo  *    written permission.
1932176cfdSRui Paulo  *
2032176cfdSRui Paulo  * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
2132176cfdSRui Paulo  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2232176cfdSRui Paulo  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2332176cfdSRui Paulo  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL David
2432176cfdSRui Paulo  * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2532176cfdSRui Paulo  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2632176cfdSRui Paulo  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2732176cfdSRui Paulo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2832176cfdSRui Paulo  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2932176cfdSRui Paulo  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3032176cfdSRui Paulo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
3132176cfdSRui Paulo  * OF SUCH DAMAGE.
3232176cfdSRui Paulo  */
3332176cfdSRui Paulo #include "opt_wlan.h"
3432176cfdSRui Paulo 
3532176cfdSRui Paulo #include <sys/param.h>
3632176cfdSRui Paulo #include <sys/kernel.h>
3732176cfdSRui Paulo #include <sys/module.h>
3832176cfdSRui Paulo #include <sys/socket.h>
3932176cfdSRui Paulo #include <sys/sysctl.h>
4032176cfdSRui Paulo 
4132176cfdSRui Paulo #include <net/if.h>
4232176cfdSRui Paulo #include <net/if_media.h>
4332176cfdSRui Paulo 
4432176cfdSRui Paulo #include <netproto/802_11/ieee80211_var.h>
4532176cfdSRui Paulo #include <netproto/802_11/ieee80211_rssadapt.h>
464028af95SRui Paulo #include <netproto/802_11/ieee80211_ratectl.h>
4732176cfdSRui Paulo 
4832176cfdSRui Paulo struct rssadapt_expavgctl {
4932176cfdSRui Paulo 	/* RSS threshold decay. */
5032176cfdSRui Paulo 	u_int rc_decay_denom;
5132176cfdSRui Paulo 	u_int rc_decay_old;
5232176cfdSRui Paulo 	/* RSS threshold update. */
5332176cfdSRui Paulo 	u_int rc_thresh_denom;
5432176cfdSRui Paulo 	u_int rc_thresh_old;
5532176cfdSRui Paulo 	/* RSS average update. */
5632176cfdSRui Paulo 	u_int rc_avgrssi_denom;
5732176cfdSRui Paulo 	u_int rc_avgrssi_old;
5832176cfdSRui Paulo };
5932176cfdSRui Paulo 
6032176cfdSRui Paulo static struct rssadapt_expavgctl master_expavgctl = {
611d8ba4b1SSascha Wildner 	.rc_decay_denom = 16,
621d8ba4b1SSascha Wildner 	.rc_decay_old = 15,
631d8ba4b1SSascha Wildner 	.rc_thresh_denom = 8,
641d8ba4b1SSascha Wildner 	.rc_thresh_old = 4,
651d8ba4b1SSascha Wildner 	.rc_avgrssi_denom = 8,
661d8ba4b1SSascha Wildner 	.rc_avgrssi_old = 4
6732176cfdSRui Paulo };
6832176cfdSRui Paulo 
6932176cfdSRui Paulo #ifdef interpolate
7032176cfdSRui Paulo #undef interpolate
7132176cfdSRui Paulo #endif
7232176cfdSRui Paulo #define interpolate(parm, old, new) ((parm##_old * (old) + \
7332176cfdSRui Paulo                                      (parm##_denom - parm##_old) * (new)) / \
7432176cfdSRui Paulo 				    parm##_denom)
7532176cfdSRui Paulo 
764028af95SRui Paulo static void	rssadapt_setinterval(const struct ieee80211vap *, int);
774028af95SRui Paulo static void	rssadapt_init(struct ieee80211vap *);
784028af95SRui Paulo static void	rssadapt_deinit(struct ieee80211vap *);
794028af95SRui Paulo static void	rssadapt_updatestats(struct ieee80211_rssadapt_node *);
804028af95SRui Paulo static void	rssadapt_node_init(struct ieee80211_node *);
814028af95SRui Paulo static void	rssadapt_node_deinit(struct ieee80211_node *);
824028af95SRui Paulo static int	rssadapt_rate(struct ieee80211_node *, void *, uint32_t);
834028af95SRui Paulo static void	rssadapt_lower_rate(struct ieee80211_rssadapt_node *, int, int);
844028af95SRui Paulo static void	rssadapt_raise_rate(struct ieee80211_rssadapt_node *,
854028af95SRui Paulo 			int, int);
864028af95SRui Paulo static void	rssadapt_tx_complete(const struct ieee80211vap *,
874028af95SRui Paulo     			const struct ieee80211_node *, int,
884028af95SRui Paulo 			void *, void *);
894028af95SRui Paulo static void	rssadapt_sysctlattach(struct ieee80211vap *,
904028af95SRui Paulo 			struct sysctl_ctx_list *, struct sysctl_oid *);
9132176cfdSRui Paulo 
9232176cfdSRui Paulo /* number of references from net80211 layer */
9332176cfdSRui Paulo static	int nrefs = 0;
9432176cfdSRui Paulo 
954028af95SRui Paulo static const struct ieee80211_ratectl rssadapt = {
964028af95SRui Paulo 	.ir_name	= "rssadapt",
974028af95SRui Paulo 	.ir_attach	= NULL,
984028af95SRui Paulo 	.ir_detach	= NULL,
994028af95SRui Paulo 	.ir_init	= rssadapt_init,
1004028af95SRui Paulo 	.ir_deinit	= rssadapt_deinit,
1014028af95SRui Paulo 	.ir_node_init	= rssadapt_node_init,
1024028af95SRui Paulo 	.ir_node_deinit	= rssadapt_node_deinit,
1034028af95SRui Paulo 	.ir_rate	= rssadapt_rate,
1044028af95SRui Paulo 	.ir_tx_complete	= rssadapt_tx_complete,
1054028af95SRui Paulo 	.ir_tx_update	= NULL,
1064028af95SRui Paulo 	.ir_setinterval	= rssadapt_setinterval,
1074028af95SRui Paulo };
1084028af95SRui Paulo IEEE80211_RATECTL_MODULE(rssadapt, 1);
1094028af95SRui Paulo IEEE80211_RATECTL_ALG(rssadapt, IEEE80211_RATECTL_RSSADAPT, rssadapt);
1104028af95SRui Paulo 
1114028af95SRui Paulo static void
1124028af95SRui Paulo rssadapt_setinterval(const struct ieee80211vap *vap, int msecs)
11332176cfdSRui Paulo {
1144028af95SRui Paulo 	struct ieee80211_rssadapt *rs = vap->iv_rs;
11532176cfdSRui Paulo 	int t;
11632176cfdSRui Paulo 
11732176cfdSRui Paulo 	if (msecs < 100)
11832176cfdSRui Paulo 		msecs = 100;
11932176cfdSRui Paulo 	t = msecs_to_ticks(msecs);
12032176cfdSRui Paulo 	rs->interval = (t < 1) ? 1 : t;
12132176cfdSRui Paulo }
12232176cfdSRui Paulo 
1234028af95SRui Paulo static void
1244028af95SRui Paulo rssadapt_init(struct ieee80211vap *vap)
12532176cfdSRui Paulo {
1264028af95SRui Paulo 	struct ieee80211_rssadapt *rs;
12732176cfdSRui Paulo 
1284028af95SRui Paulo 	KASSERT(vap->iv_rs == NULL, ("%s: iv_rs already initialized",
1294028af95SRui Paulo 	    __func__));
1304028af95SRui Paulo 
1314028af95SRui Paulo 	rs = kmalloc(sizeof(struct ieee80211_rssadapt), M_80211_RATECTL,
1324028af95SRui Paulo 	    M_WAITOK|M_ZERO);
1334028af95SRui Paulo 	vap->iv_rs = rs;
1344028af95SRui Paulo 	rs->vap = vap;
1354028af95SRui Paulo 	rssadapt_setinterval(vap, 500 /* msecs */);
1364028af95SRui Paulo 	rssadapt_sysctlattach(vap, vap->iv_sysctl, vap->iv_oid);
13732176cfdSRui Paulo }
13832176cfdSRui Paulo 
1394028af95SRui Paulo static void
1404028af95SRui Paulo rssadapt_deinit(struct ieee80211vap *vap)
14132176cfdSRui Paulo {
1424028af95SRui Paulo 	kfree(vap->iv_rs, M_80211_RATECTL);
14332176cfdSRui Paulo }
14432176cfdSRui Paulo 
14532176cfdSRui Paulo static void
14632176cfdSRui Paulo rssadapt_updatestats(struct ieee80211_rssadapt_node *ra)
14732176cfdSRui Paulo {
14832176cfdSRui Paulo 	long interval;
14932176cfdSRui Paulo 
15032176cfdSRui Paulo 	ra->ra_pktrate = (ra->ra_pktrate + 10*(ra->ra_nfail + ra->ra_nok))/2;
15132176cfdSRui Paulo 	ra->ra_nfail = ra->ra_nok = 0;
15232176cfdSRui Paulo 
15332176cfdSRui Paulo 	/*
15432176cfdSRui Paulo 	 * A node is eligible for its rate to be raised every 1/10 to 10
15532176cfdSRui Paulo 	 * seconds, more eligible in proportion to recent packet rates.
15632176cfdSRui Paulo 	 */
15732176cfdSRui Paulo 	interval = MAX(10*1000, 10*1000 / MAX(1, 10 * ra->ra_pktrate));
15832176cfdSRui Paulo 	ra->ra_raise_interval = msecs_to_ticks(interval);
15932176cfdSRui Paulo }
16032176cfdSRui Paulo 
1614028af95SRui Paulo static void
1624028af95SRui Paulo rssadapt_node_init(struct ieee80211_node *ni)
16332176cfdSRui Paulo {
1644028af95SRui Paulo 	struct ieee80211_rssadapt_node *ra;
1654028af95SRui Paulo 	struct ieee80211_rssadapt *rsa = ni->ni_vap->iv_rs;
16632176cfdSRui Paulo 	const struct ieee80211_rateset *rs = &ni->ni_rates;
16732176cfdSRui Paulo 
168*a72c14d0SSascha Wildner 	if (ni->ni_rctls == NULL) {
169*a72c14d0SSascha Wildner 		ni->ni_rctls = ra =
170*a72c14d0SSascha Wildner 		    kmalloc(sizeof(struct ieee80211_rssadapt_node),
171*a72c14d0SSascha Wildner 			M_80211_RATECTL, M_WAITOK|M_ZERO);
172*a72c14d0SSascha Wildner 	} else {
173*a72c14d0SSascha Wildner 		ra = ni->ni_rctls;
174*a72c14d0SSascha Wildner 	}
17532176cfdSRui Paulo 	ra->ra_rs = rsa;
17632176cfdSRui Paulo 	ra->ra_rates = *rs;
17732176cfdSRui Paulo 	rssadapt_updatestats(ra);
17832176cfdSRui Paulo 
17932176cfdSRui Paulo 	/* pick initial rate */
18032176cfdSRui Paulo 	for (ra->ra_rix = rs->rs_nrates - 1;
18132176cfdSRui Paulo 	     ra->ra_rix > 0 && (rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL) > 72;
18232176cfdSRui Paulo 	     ra->ra_rix--)
18332176cfdSRui Paulo 		;
18432176cfdSRui Paulo 	ni->ni_txrate = rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL;
18532176cfdSRui Paulo 	ra->ra_ticks = ticks;
18632176cfdSRui Paulo 
18732176cfdSRui Paulo 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
18832176cfdSRui Paulo 	    "RSSADAPT initial rate %d", ni->ni_txrate);
18932176cfdSRui Paulo }
19032176cfdSRui Paulo 
1914028af95SRui Paulo static void
1924028af95SRui Paulo rssadapt_node_deinit(struct ieee80211_node *ni)
1934028af95SRui Paulo {
1944028af95SRui Paulo 
1954028af95SRui Paulo 	kfree(ni->ni_rctls, M_80211_RATECTL);
1964028af95SRui Paulo }
1974028af95SRui Paulo 
19832176cfdSRui Paulo static __inline int
19932176cfdSRui Paulo bucket(int pktlen)
20032176cfdSRui Paulo {
20132176cfdSRui Paulo 	int i, top, thridx;
20232176cfdSRui Paulo 
20332176cfdSRui Paulo 	for (i = 0, top = IEEE80211_RSSADAPT_BKT0;
20432176cfdSRui Paulo 	     i < IEEE80211_RSSADAPT_BKTS;
20532176cfdSRui Paulo 	     i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) {
20632176cfdSRui Paulo 		thridx = i;
20732176cfdSRui Paulo 		if (pktlen <= top)
20832176cfdSRui Paulo 			break;
20932176cfdSRui Paulo 	}
21032176cfdSRui Paulo 	return thridx;
21132176cfdSRui Paulo }
21232176cfdSRui Paulo 
2134028af95SRui Paulo static int
2144028af95SRui Paulo rssadapt_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg)
21532176cfdSRui Paulo {
2164028af95SRui Paulo 	struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
2174028af95SRui Paulo 	u_int pktlen = iarg;
21832176cfdSRui Paulo 	const struct ieee80211_rateset *rs = &ra->ra_rates;
21932176cfdSRui Paulo 	uint16_t (*thrs)[IEEE80211_RATE_SIZE];
22032176cfdSRui Paulo 	int rix, rssi;
22132176cfdSRui Paulo 
22232176cfdSRui Paulo 	if ((ticks - ra->ra_ticks) > ra->ra_rs->interval) {
22332176cfdSRui Paulo 		rssadapt_updatestats(ra);
22432176cfdSRui Paulo 		ra->ra_ticks = ticks;
22532176cfdSRui Paulo 	}
22632176cfdSRui Paulo 
22732176cfdSRui Paulo 	thrs = &ra->ra_rate_thresh[bucket(pktlen)];
22832176cfdSRui Paulo 
22932176cfdSRui Paulo 	/* XXX this is average rssi, should be using last value */
23032176cfdSRui Paulo 	rssi = ni->ni_ic->ic_node_getrssi(ni);
23132176cfdSRui Paulo 	for (rix = rs->rs_nrates-1; rix >= 0; rix--)
23232176cfdSRui Paulo 		if ((*thrs)[rix] < (rssi << 8))
23332176cfdSRui Paulo 			break;
23432176cfdSRui Paulo 	if (rix != ra->ra_rix) {
23532176cfdSRui Paulo 		/* update public rate */
23632176cfdSRui Paulo 		ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL;
23732176cfdSRui Paulo 		ra->ra_rix = rix;
23832176cfdSRui Paulo 
23932176cfdSRui Paulo 		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
24032176cfdSRui Paulo 		    "RSSADAPT new rate %d (pktlen %d rssi %d)",
24132176cfdSRui Paulo 		    ni->ni_txrate, pktlen, rssi);
24232176cfdSRui Paulo 	}
24332176cfdSRui Paulo 	return rix;
24432176cfdSRui Paulo }
24532176cfdSRui Paulo 
24632176cfdSRui Paulo /*
24732176cfdSRui Paulo  * Adapt the data rate to suit the conditions.  When a transmitted
24832176cfdSRui Paulo  * packet is dropped after RAL_RSSADAPT_RETRY_LIMIT retransmissions,
24932176cfdSRui Paulo  * raise the RSS threshold for transmitting packets of similar length at
25032176cfdSRui Paulo  * the same data rate.
25132176cfdSRui Paulo  */
2524028af95SRui Paulo static void
2534028af95SRui Paulo rssadapt_lower_rate(struct ieee80211_rssadapt_node *ra, int pktlen, int rssi)
25432176cfdSRui Paulo {
25532176cfdSRui Paulo 	uint16_t last_thr;
25632176cfdSRui Paulo 	uint16_t (*thrs)[IEEE80211_RATE_SIZE];
25732176cfdSRui Paulo 	u_int rix;
25832176cfdSRui Paulo 
25932176cfdSRui Paulo 	thrs = &ra->ra_rate_thresh[bucket(pktlen)];
26032176cfdSRui Paulo 
26132176cfdSRui Paulo 	rix = ra->ra_rix;
26232176cfdSRui Paulo 	last_thr = (*thrs)[rix];
26332176cfdSRui Paulo 	(*thrs)[rix] = interpolate(master_expavgctl.rc_thresh,
26432176cfdSRui Paulo 	    last_thr, (rssi << 8));
26532176cfdSRui Paulo 
26632176cfdSRui Paulo 	IEEE80211_DPRINTF(ra->ra_rs->vap, IEEE80211_MSG_RATECTL,
26732176cfdSRui Paulo 	    "RSSADAPT lower threshold for rate %d (last_thr %d new thr %d rssi %d)\n",
26832176cfdSRui Paulo 	    ra->ra_rates.rs_rates[rix + 1] & IEEE80211_RATE_VAL,
26932176cfdSRui Paulo 	    last_thr, (*thrs)[rix], rssi);
27032176cfdSRui Paulo }
27132176cfdSRui Paulo 
2724028af95SRui Paulo static void
2734028af95SRui Paulo rssadapt_raise_rate(struct ieee80211_rssadapt_node *ra, int pktlen, int rssi)
27432176cfdSRui Paulo {
27532176cfdSRui Paulo 	uint16_t (*thrs)[IEEE80211_RATE_SIZE];
27632176cfdSRui Paulo 	uint16_t newthr, oldthr;
27732176cfdSRui Paulo 	int rix;
27832176cfdSRui Paulo 
27932176cfdSRui Paulo 	thrs = &ra->ra_rate_thresh[bucket(pktlen)];
28032176cfdSRui Paulo 
28132176cfdSRui Paulo 	rix = ra->ra_rix;
28232176cfdSRui Paulo 	if ((*thrs)[rix + 1] > (*thrs)[rix]) {
28332176cfdSRui Paulo 		oldthr = (*thrs)[rix + 1];
28432176cfdSRui Paulo 		if ((*thrs)[rix] == 0)
28532176cfdSRui Paulo 			newthr = (rssi << 8);
28632176cfdSRui Paulo 		else
28732176cfdSRui Paulo 			newthr = (*thrs)[rix];
28832176cfdSRui Paulo 		(*thrs)[rix + 1] = interpolate(master_expavgctl.rc_decay,
28932176cfdSRui Paulo 		    oldthr, newthr);
29032176cfdSRui Paulo 
29132176cfdSRui Paulo 		IEEE80211_DPRINTF(ra->ra_rs->vap, IEEE80211_MSG_RATECTL,
29232176cfdSRui Paulo 		    "RSSADAPT raise threshold for rate %d (oldthr %d newthr %d rssi %d)\n",
29332176cfdSRui Paulo 		    ra->ra_rates.rs_rates[rix + 1] & IEEE80211_RATE_VAL,
29432176cfdSRui Paulo 		    oldthr, newthr, rssi);
29532176cfdSRui Paulo 
29632176cfdSRui Paulo 		ra->ra_last_raise = ticks;
29732176cfdSRui Paulo 	}
29832176cfdSRui Paulo }
29932176cfdSRui Paulo 
3004028af95SRui Paulo static void
3014028af95SRui Paulo rssadapt_tx_complete(const struct ieee80211vap *vap,
3024028af95SRui Paulo     const struct ieee80211_node *ni, int success, void *arg1, void *arg2)
3034028af95SRui Paulo {
3044028af95SRui Paulo 	struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
3054028af95SRui Paulo 	int pktlen = *(int *)arg1, rssi = *(int *)arg2;
3064028af95SRui Paulo 
3074028af95SRui Paulo 	if (success) {
3084028af95SRui Paulo 		ra->ra_nok++;
3094028af95SRui Paulo 		if ((ra->ra_rix + 1) < ra->ra_rates.rs_nrates &&
3104028af95SRui Paulo 		    (ticks - ra->ra_last_raise) >= ra->ra_raise_interval)
3114028af95SRui Paulo 			rssadapt_raise_rate(ra, pktlen, rssi);
3124028af95SRui Paulo 	} else {
3134028af95SRui Paulo 		ra->ra_nfail++;
3144028af95SRui Paulo 		rssadapt_lower_rate(ra, pktlen, rssi);
3154028af95SRui Paulo 	}
3164028af95SRui Paulo }
3174028af95SRui Paulo 
31832176cfdSRui Paulo static int
31932176cfdSRui Paulo rssadapt_sysctl_interval(SYSCTL_HANDLER_ARGS)
32032176cfdSRui Paulo {
3214028af95SRui Paulo 	struct ieee80211vap *vap = arg1;
3224028af95SRui Paulo 	struct ieee80211_rssadapt *rs = vap->iv_rs;
32332176cfdSRui Paulo 	int msecs = ticks_to_msecs(rs->interval);
32432176cfdSRui Paulo 	int error;
32532176cfdSRui Paulo 
32632176cfdSRui Paulo 	error = sysctl_handle_int(oidp, &msecs, 0, req);
32747156d48SMatthew Dillon 	wlan_serialize_enter();
32847156d48SMatthew Dillon 	if (error == 0 && req->newptr)
3294028af95SRui Paulo 		rssadapt_setinterval(vap, msecs);
33047156d48SMatthew Dillon 	wlan_serialize_exit();
33147156d48SMatthew Dillon 
33247156d48SMatthew Dillon 	return error;
33332176cfdSRui Paulo }
33432176cfdSRui Paulo 
33532176cfdSRui Paulo static void
3364028af95SRui Paulo rssadapt_sysctlattach(struct ieee80211vap *vap,
33732176cfdSRui Paulo     struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
33832176cfdSRui Paulo {
33932176cfdSRui Paulo 
34032176cfdSRui Paulo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
3414028af95SRui Paulo 	    "rssadapt_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap,
34232176cfdSRui Paulo 	    0, rssadapt_sysctl_interval, "I", "rssadapt operation interval (ms)");
34332176cfdSRui Paulo }
344