1295016Sjkim/*-
2109998Smarkm * SPDX-License-Identifier: BSD-2-Clause
3109998Smarkm *
4109998Smarkm * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
5109998Smarkm * All rights reserved.
6109998Smarkm *
7109998Smarkm * Redistribution and use in source and binary forms, with or without
8109998Smarkm * modification, are permitted provided that the following conditions
9109998Smarkm * are met:
10109998Smarkm * 1. Redistributions of source code must retain the above copyright
11109998Smarkm *    notice, this list of conditions and the following disclaimer,
12109998Smarkm *    without modification.
13109998Smarkm * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14109998Smarkm *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15109998Smarkm *    redistribution must be conditioned upon including a substantially
16109998Smarkm *    similar Disclaimer requirement for further binary redistribution.
17109998Smarkm *
18109998Smarkm * NO WARRANTY
19109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20109998Smarkm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21109998Smarkm * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22109998Smarkm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23109998Smarkm * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24109998Smarkm * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25109998Smarkm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26109998Smarkm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27109998Smarkm * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29109998Smarkm * THE POSSIBILITY OF SUCH DAMAGES.
30109998Smarkm */
31109998Smarkm
32109998Smarkm#include <sys/cdefs.h>
33109998Smarkm/*
34109998Smarkm * Atsushi Onoe's rate control algorithm.
35109998Smarkm */
36109998Smarkm#include "opt_ath.h"
37109998Smarkm#include "opt_inet.h"
38109998Smarkm#include "opt_wlan.h"
39109998Smarkm
40109998Smarkm#include <sys/param.h>
41109998Smarkm#include <sys/systm.h>
42238405Sjkim#include <sys/sysctl.h>
43280304Sjkim#include <sys/kernel.h>
44109998Smarkm#include <sys/lock.h>
45109998Smarkm#include <sys/mutex.h>
46109998Smarkm#include <sys/errno.h>
47109998Smarkm
48109998Smarkm#include <machine/bus.h>
49109998Smarkm#include <machine/resource.h>
50109998Smarkm#include <sys/bus.h>
51109998Smarkm
52109998Smarkm#include <sys/socket.h>
53162911Ssimon
54109998Smarkm#include <net/if.h>
55109998Smarkm#include <net/if_media.h>
56109998Smarkm#include <net/if_arp.h>
57109998Smarkm#include <net/ethernet.h>		/* XXX for ether_sprintf */
58109998Smarkm
59109998Smarkm#include <net80211/ieee80211_var.h>
60109998Smarkm
61109998Smarkm#include <net/bpf.h>
62109998Smarkm
63109998Smarkm#ifdef INET
64109998Smarkm#include <netinet/in.h>
65109998Smarkm#include <netinet/if_ether.h>
66109998Smarkm#endif
67109998Smarkm
68109998Smarkm#include <dev/ath/if_athvar.h>
69109998Smarkm#include <dev/ath/ath_rate/onoe/onoe.h>
70109998Smarkm#include <dev/ath/ath_hal/ah_desc.h>
71109998Smarkm
72109998Smarkm/*
73109998Smarkm * Default parameters for the rate control algorithm.  These are
74109998Smarkm * all tunable with sysctls.  The rate controller runs periodically
75109998Smarkm * (each ath_rateinterval ms) analyzing transmit statistics for each
76109998Smarkm * neighbor/station (when operating in station mode this is only the AP).
77109998Smarkm * If transmits look to be working well over a sampling period then
78109998Smarkm * it gives a "raise rate credit".  If transmits look to not be working
79109998Smarkm * well than it deducts a credit.  If the credits cross a threshold then
80109998Smarkm * the transmit rate is raised.  Various error conditions force the
81109998Smarkm * the transmit rate to be dropped.
82109998Smarkm *
83109998Smarkm * The decision to issue/deduct a credit is based on the errors and
84109998Smarkm * retries accumulated over the sampling period.  ath_rate_raise defines
85109998Smarkm * the percent of retransmits for which a credit is issued/deducted.
86109998Smarkm * ath_rate_raise_threshold defines the threshold on credits at which
87109998Smarkm * the transmit rate is increased.
88109998Smarkm *
89109998Smarkm * XXX this algorithm is flawed.
90109998Smarkm */
91109998Smarkmstatic	int ath_rateinterval = 1000;		/* rate ctl interval (ms)  */
92109998Smarkmstatic	int ath_rate_raise = 10;		/* add credit threshold */
93109998Smarkmstatic	int ath_rate_raise_threshold = 10;	/* rate ctl raise threshold */
94109998Smarkm
95109998Smarkmstatic void	ath_rate_update(struct ath_softc *, struct ieee80211_node *,
96109998Smarkm			int rate);
97109998Smarkmstatic void	ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *);
98109998Smarkmstatic void	ath_rate_ctl(void *, struct ieee80211_node *);
99109998Smarkm
100109998Smarkmvoid
101109998Smarkmath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
102109998Smarkm{
103109998Smarkm	/* NB: assumed to be zero'd by caller */
104109998Smarkm}
105109998Smarkm
106109998Smarkmvoid
107109998Smarkmath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
108109998Smarkm{
109109998Smarkm}
110109998Smarkm
111109998Smarkmvoid
112109998Smarkmath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
113109998Smarkm	int shortPreamble, size_t frameLen, int tid, int is_aggr,
114109998Smarkm	u_int8_t *rix, int *try0, u_int8_t *txrate, int *maxdur,
115109998Smarkm	int *maxpktlen)
116109998Smarkm{
117109998Smarkm	struct onoe_node *on = ATH_NODE_ONOE(an);
118109998Smarkm
119109998Smarkm	*rix = on->on_tx_rix0;
120109998Smarkm	*try0 = on->on_tx_try0;
121109998Smarkm	if (shortPreamble)
122109998Smarkm		*txrate = on->on_tx_rate0sp;
123109998Smarkm	else
124109998Smarkm		*txrate = on->on_tx_rate0;
125109998Smarkm	*maxdur = -1;
126109998Smarkm	*maxpktlen = -1;
127109998Smarkm}
128109998Smarkm
129109998Smarkm/*
130109998Smarkm * Get the TX rates.
131109998Smarkm *
132109998Smarkm * The short preamble bits aren't set here; the caller should augment
133109998Smarkm * the returned rate with the relevant preamble rate flag.
134109998Smarkm */
135109998Smarkmvoid
136109998Smarkmath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
137109998Smarkm    uint8_t rix0, int is_aggr, struct ath_rc_series *rc)
138109998Smarkm{
139109998Smarkm	struct onoe_node *on = ATH_NODE_ONOE(an);
140109998Smarkm
141109998Smarkm	rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
142109998Smarkm
143109998Smarkm	rc[0].rix = on->on_tx_rate0;
144109998Smarkm	rc[1].rix = on->on_tx_rate1;
145109998Smarkm	rc[2].rix = on->on_tx_rate2;
146109998Smarkm	rc[3].rix = on->on_tx_rate3;
147109998Smarkm
148109998Smarkm	rc[0].tries = on->on_tx_try0;
149109998Smarkm	rc[1].tries = 2;
150109998Smarkm	rc[2].tries = 2;
151109998Smarkm	rc[3].tries = 2;
152109998Smarkm}
153109998Smarkm
154109998Smarkmvoid
155109998Smarkmath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
156109998Smarkm	struct ath_desc *ds, int shortPreamble, u_int8_t rix)
157109998Smarkm{
158109998Smarkm	struct onoe_node *on = ATH_NODE_ONOE(an);
159109998Smarkm
160109998Smarkm	ath_hal_setupxtxdesc(sc->sc_ah, ds
161109998Smarkm		, on->on_tx_rate1sp, 2	/* series 1 */
162109998Smarkm		, on->on_tx_rate2sp, 2	/* series 2 */
163109998Smarkm		, on->on_tx_rate3sp, 2	/* series 3 */
164109998Smarkm	);
165109998Smarkm}
166109998Smarkm
167109998Smarkmvoid
168109998Smarkmath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
169109998Smarkm	const struct ath_rc_series *rc, const struct ath_tx_status *ts,
170109998Smarkm	int frame_size, int rc_framesize, int nframes, int nbad)
171109998Smarkm{
172109998Smarkm	struct onoe_node *on = ATH_NODE_ONOE(an);
173109998Smarkm
174109998Smarkm	if (ts->ts_status == 0)
175109998Smarkm		on->on_tx_ok++;
176109998Smarkm	else
177109998Smarkm		on->on_tx_err++;
178109998Smarkm	on->on_tx_retr += ts->ts_shortretry
179109998Smarkm			+ ts->ts_longretry;
180109998Smarkm	if (on->on_interval != 0 && ticks - on->on_ticks > on->on_interval) {
181109998Smarkm		ath_rate_ctl(sc, &an->an_node);
182109998Smarkm		on->on_ticks = ticks;
183109998Smarkm	}
184109998Smarkm}
185109998Smarkm
186109998Smarkmvoid
187109998Smarkmath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
188109998Smarkm{
189109998Smarkm	if (isnew)
190109998Smarkm		ath_rate_ctl_start(sc, &an->an_node);
191109998Smarkm}
192109998Smarkm
193109998Smarkmvoid
194109998Smarkmath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)
195109998Smarkm{
196109998Smarkm}
197109998Smarkm
198109998Smarkmstatic void
199109998Smarkmath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)
200109998Smarkm{
201109998Smarkm	struct ath_node *an = ATH_NODE(ni);
202109998Smarkm	struct onoe_node *on = ATH_NODE_ONOE(an);
203109998Smarkm	struct ieee80211vap *vap = ni->ni_vap;
204109998Smarkm	const HAL_RATE_TABLE *rt = sc->sc_currates;
205109998Smarkm	u_int8_t rix;
206109998Smarkm
207109998Smarkm	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
208109998Smarkm
209109998Smarkm	IEEE80211_NOTE(vap, IEEE80211_MSG_RATECTL, ni,
210109998Smarkm	     "%s: set xmit rate to %dM", __func__,
211109998Smarkm	     ni->ni_rates.rs_nrates > 0 ?
212109998Smarkm		(ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);
213109998Smarkm
214109998Smarkm	/*
215109998Smarkm	 * Before associating a node has no rate set setup
216109998Smarkm	 * so we can't calculate any transmit codes to use.
217109998Smarkm	 * This is ok since we should never be sending anything
218109998Smarkm	 * but management frames and those always go at the
219109998Smarkm	 * lowest hardware rate.
220109998Smarkm	 */
221109998Smarkm	if (ni->ni_rates.rs_nrates == 0)
222109998Smarkm		goto done;
223109998Smarkm	on->on_rix = rate;
224109998Smarkm	ni->ni_txrate = ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL;
225109998Smarkm	on->on_tx_rix0 = sc->sc_rixmap[ni->ni_txrate];
226109998Smarkm	on->on_tx_rate0 = rt->info[on->on_tx_rix0].rateCode;
227109998Smarkm
228109998Smarkm	on->on_tx_rate0sp = on->on_tx_rate0 |
229109998Smarkm		rt->info[on->on_tx_rix0].shortPreamble;
230109998Smarkm	if (sc->sc_mrretry) {
231109998Smarkm		/*
232109998Smarkm		 * Hardware supports multi-rate retry; setup two
233109998Smarkm		 * step-down retry rates and make the lowest rate
234109998Smarkm		 * be the ``last chance''.  We use 4, 2, 2, 2 tries
235109998Smarkm		 * respectively (4 is set here, the rest are fixed
236109998Smarkm		 * in the xmit routine).
237109998Smarkm		 */
238109998Smarkm		on->on_tx_try0 = 1 + 3;		/* 4 tries at rate 0 */
239109998Smarkm		if (--rate >= 0) {
240109998Smarkm			rix = sc->sc_rixmap[
241109998Smarkm				ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
242109998Smarkm			on->on_tx_rate1 = rt->info[rix].rateCode;
243109998Smarkm			on->on_tx_rate1sp = on->on_tx_rate1 |
244109998Smarkm				rt->info[rix].shortPreamble;
245109998Smarkm		} else {
246109998Smarkm			on->on_tx_rate1 = on->on_tx_rate1sp = 0;
247109998Smarkm		}
248109998Smarkm		if (--rate >= 0) {
249109998Smarkm			rix = sc->sc_rixmap[
250109998Smarkm				ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
251109998Smarkm			on->on_tx_rate2 = rt->info[rix].rateCode;
252109998Smarkm			on->on_tx_rate2sp = on->on_tx_rate2 |
253109998Smarkm				rt->info[rix].shortPreamble;
254109998Smarkm		} else {
255109998Smarkm			on->on_tx_rate2 = on->on_tx_rate2sp = 0;
256109998Smarkm		}
257109998Smarkm		if (rate > 0) {
258109998Smarkm			/* NB: only do this if we didn't already do it above */
259109998Smarkm			on->on_tx_rate3 = rt->info[0].rateCode;
260109998Smarkm			on->on_tx_rate3sp =
261109998Smarkm				on->on_tx_rate3 | rt->info[0].shortPreamble;
262109998Smarkm		} else {
263109998Smarkm			on->on_tx_rate3 = on->on_tx_rate3sp = 0;
264109998Smarkm		}
265109998Smarkm	} else {
266109998Smarkm		on->on_tx_try0 = ATH_TXMAXTRY;	/* max tries at rate 0 */
267109998Smarkm		on->on_tx_rate1 = on->on_tx_rate1sp = 0;
268109998Smarkm		on->on_tx_rate2 = on->on_tx_rate2sp = 0;
269109998Smarkm		on->on_tx_rate3 = on->on_tx_rate3sp = 0;
270109998Smarkm	}
271109998Smarkmdone:
272109998Smarkm	on->on_tx_ok = on->on_tx_err = on->on_tx_retr = on->on_tx_upper = 0;
273109998Smarkm
274109998Smarkm	on->on_interval = ath_rateinterval;
275109998Smarkm	if (vap->iv_opmode == IEEE80211_M_STA)
276109998Smarkm		on->on_interval /= 2;
277109998Smarkm	on->on_interval = (on->on_interval * hz) / 1000;
278109998Smarkm}
279109998Smarkm
280109998Smarkm/*
281109998Smarkm * Set the starting transmit rate for a node.
282109998Smarkm */
283109998Smarkmstatic void
284109998Smarkmath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
285109998Smarkm{
286109998Smarkm#define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
287109998Smarkm	const struct ieee80211_txparam *tp = ni->ni_txparms;
288109998Smarkm	int srate;
289109998Smarkm
290109998Smarkm	KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates"));
291109998Smarkm	if (tp == NULL || tp->ucastrate == IEEE80211_FIXED_RATE_NONE) {
292109998Smarkm		/*
293109998Smarkm		 * No fixed rate is requested. For 11b start with
294109998Smarkm		 * the highest negotiated rate; otherwise, for 11g
295109998Smarkm		 * and 11a, we start "in the middle" at 24Mb or 36Mb.
296109998Smarkm		 */
297109998Smarkm		srate = ni->ni_rates.rs_nrates - 1;
298109998Smarkm		if (sc->sc_curmode != IEEE80211_MODE_11B) {
299109998Smarkm			/*
300109998Smarkm			 * Scan the negotiated rate set to find the
301109998Smarkm			 * closest rate.
302109998Smarkm			 */
303109998Smarkm			/* NB: the rate set is assumed sorted */
304109998Smarkm			for (; srate >= 0 && RATE(srate) > 72; srate--)
305109998Smarkm				;
306109998Smarkm		}
307109998Smarkm	} else {
308109998Smarkm		/*
309109998Smarkm		 * A fixed rate is to be used; ic_fixed_rate is the
310109998Smarkm		 * IEEE code for this rate (sans basic bit).  Convert this
311109998Smarkm		 * to the index into the negotiated rate set for
312109998Smarkm		 * the node.  We know the rate is there because the
313109998Smarkm		 * rate set is checked when the station associates.
314109998Smarkm		 */
315109998Smarkm		/* NB: the rate set is assumed sorted */
316109998Smarkm		srate = ni->ni_rates.rs_nrates - 1;
317109998Smarkm		for (; srate >= 0 && RATE(srate) != tp->ucastrate; srate--)
318109998Smarkm			;
319109998Smarkm	}
320160814Ssimon	/*
321109998Smarkm	 * The selected rate may not be available due to races
322109998Smarkm	 * and mode settings.  Also orphaned nodes created in
323109998Smarkm	 * adhoc mode may not have any rate set so this lookup
324109998Smarkm	 * can fail.  This is not fatal.
325109998Smarkm	 */
326109998Smarkm	ath_rate_update(sc, ni, srate < 0 ? 0 : srate);
327109998Smarkm#undef RATE
328109998Smarkm}
329109998Smarkm
330109998Smarkm/*
331109998Smarkm * Examine and potentially adjust the transmit rate.
332109998Smarkm */
333109998Smarkmstatic void
334109998Smarkmath_rate_ctl(void *arg, struct ieee80211_node *ni)
335109998Smarkm{
336109998Smarkm	struct ath_softc *sc = arg;
337109998Smarkm	struct onoe_node *on = ATH_NODE_ONOE(ATH_NODE(ni));
338109998Smarkm	struct ieee80211_rateset *rs = &ni->ni_rates;
339109998Smarkm	int dir = 0, nrate, enough;
340109998Smarkm
341109998Smarkm	/*
342109998Smarkm	 * Rate control
343109998Smarkm	 * XXX: very primitive version.
344109998Smarkm	 */
345109998Smarkm	enough = (on->on_tx_ok + on->on_tx_err >= 10);
346109998Smarkm
347109998Smarkm	/* no packet reached -> down */
348109998Smarkm	if (on->on_tx_err > 0 && on->on_tx_ok == 0)
349109998Smarkm		dir = -1;
350109998Smarkm
351109998Smarkm	/* all packets needs retry in average -> down */
352109998Smarkm	if (enough && on->on_tx_ok < on->on_tx_retr)
353109998Smarkm		dir = -1;
354109998Smarkm
355109998Smarkm	/* no error and less than rate_raise% of packets need retry -> up */
356109998Smarkm	if (enough && on->on_tx_err == 0 &&
357109998Smarkm	    on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100)
358109998Smarkm		dir = 1;
359109998Smarkm
360109998Smarkm	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
361109998Smarkm	    "ok %d err %d retr %d upper %d dir %d",
362109998Smarkm	    on->on_tx_ok, on->on_tx_err, on->on_tx_retr, on->on_tx_upper, dir);
363109998Smarkm
364109998Smarkm	nrate = on->on_rix;
365109998Smarkm	switch (dir) {
366109998Smarkm	case 0:
367109998Smarkm		if (enough && on->on_tx_upper > 0)
368109998Smarkm			on->on_tx_upper--;
369109998Smarkm		break;
370109998Smarkm	case -1:
371109998Smarkm		if (nrate > 0) {
372109998Smarkm			nrate--;
373109998Smarkm			sc->sc_stats.ast_rate_drop++;
374109998Smarkm		}
375109998Smarkm		on->on_tx_upper = 0;
376109998Smarkm		break;
377109998Smarkm	case 1:
378109998Smarkm		/* raise rate if we hit rate_raise_threshold */
379109998Smarkm		if (++on->on_tx_upper < ath_rate_raise_threshold)
380109998Smarkm			break;
381109998Smarkm		on->on_tx_upper = 0;
382109998Smarkm		if (nrate + 1 < rs->rs_nrates) {
383109998Smarkm			nrate++;
384109998Smarkm			sc->sc_stats.ast_rate_raise++;
385109998Smarkm		}
386109998Smarkm		break;
387109998Smarkm	}
388109998Smarkm
389109998Smarkm	if (nrate != on->on_rix) {
390109998Smarkm		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
391109998Smarkm		    "%s: %dM -> %dM (%d ok, %d err, %d retr)", __func__,
392109998Smarkm		    ni->ni_txrate / 2,
393109998Smarkm		    (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2,
394109998Smarkm		    on->on_tx_ok, on->on_tx_err, on->on_tx_retr);
395109998Smarkm		ath_rate_update(sc, ni, nrate);
396109998Smarkm	} else if (enough)
397109998Smarkm		on->on_tx_ok = on->on_tx_err = on->on_tx_retr = 0;
398109998Smarkm}
399109998Smarkm
400109998Smarkmstatic void
401109998Smarkmath_rate_sysctlattach(struct ath_softc *sc)
402109998Smarkm{
403109998Smarkm	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
404109998Smarkm	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
405109998Smarkm
406109998Smarkm	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
407109998Smarkm		"rate_interval", CTLFLAG_RW, &ath_rateinterval, 0,
408109998Smarkm		"rate control: operation interval (ms)");
409109998Smarkm	/* XXX bounds check values */
410109998Smarkm	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
411109998Smarkm		"rate_raise", CTLFLAG_RW, &ath_rate_raise, 0,
412109998Smarkm		"rate control: retry threshold to credit rate raise (%%)");
413109998Smarkm	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
414109998Smarkm		"rate_raise_threshold", CTLFLAG_RW, &ath_rate_raise_threshold,0,
415109998Smarkm		"rate control: # good periods before raising rate");
416109998Smarkm}
417109998Smarkm
418109998Smarkmstatic int
419109998Smarkmath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
420109998Smarkm    struct ath_rateioctl *re)
421109998Smarkm{
422109998Smarkm
423109998Smarkm	return (EINVAL);
424109998Smarkm}
425109998Smarkm
426109998Smarkmstruct ath_ratectrl *
427109998Smarkmath_rate_attach(struct ath_softc *sc)
428109998Smarkm{
429109998Smarkm	struct onoe_softc *osc;
430109998Smarkm
431109998Smarkm	osc = malloc(sizeof(struct onoe_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
432109998Smarkm	if (osc == NULL)
433109998Smarkm		return NULL;
434109998Smarkm	osc->arc.arc_space = sizeof(struct onoe_node);
435109998Smarkm	ath_rate_sysctlattach(sc);
436109998Smarkm
437109998Smarkm	return &osc->arc;
438109998Smarkm}
439109998Smarkm
440109998Smarkmvoid
441109998Smarkmath_rate_detach(struct ath_ratectrl *arc)
442109998Smarkm{
443109998Smarkm	struct onoe_softc *osc = (struct onoe_softc *) arc;
444109998Smarkm
445109998Smarkm	free(osc, M_DEVBUF);
446109998Smarkm}
447109998Smarkm