1b6108616SRui Paulo /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4b6108616SRui Paulo * Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
5b6108616SRui Paulo * All rights reserved.
6b6108616SRui Paulo *
7b6108616SRui Paulo * Redistribution and use in source and binary forms, with or without
8b6108616SRui Paulo * modification, are permitted provided that the following conditions
9b6108616SRui Paulo * are met:
10b6108616SRui Paulo * 1. Redistributions of source code must retain the above copyright
11b6108616SRui Paulo * notice, this list of conditions and the following disclaimer.
12b6108616SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright
13b6108616SRui Paulo * notice, this list of conditions and the following disclaimer in the
14b6108616SRui Paulo * documentation and/or other materials provided with the distribution.
15b6108616SRui Paulo *
16b6108616SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17b6108616SRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18b6108616SRui Paulo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19b6108616SRui Paulo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20b6108616SRui Paulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21b6108616SRui Paulo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22b6108616SRui Paulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23b6108616SRui Paulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24b6108616SRui Paulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25b6108616SRui Paulo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26b6108616SRui Paulo */
27b6108616SRui Paulo
28b6108616SRui Paulo #include <sys/param.h>
29b6108616SRui Paulo #include <sys/kernel.h>
3073931706SAdrian Chadd #include <sys/sbuf.h>
31b6108616SRui Paulo #include <sys/systm.h>
32b6108616SRui Paulo #include <sys/socket.h>
33eedc7fd9SGleb Smirnoff #include <sys/malloc.h>
34b6108616SRui Paulo
35b6108616SRui Paulo #include <net/if.h>
36b6108616SRui Paulo #include <net/if_media.h>
37eedc7fd9SGleb Smirnoff #include <net/ethernet.h>
38eedc7fd9SGleb Smirnoff #include <net/route.h>
39b6108616SRui Paulo
40b6108616SRui Paulo #include <net80211/ieee80211_var.h>
41b6108616SRui Paulo #include <net80211/ieee80211_ratectl.h>
42b6108616SRui Paulo
43b6108616SRui Paulo static const struct ieee80211_ratectl *ratectls[IEEE80211_RATECTL_MAX];
44b6108616SRui Paulo
459a9a302fSBernhard Schmidt static const char *ratectl_modnames[IEEE80211_RATECTL_MAX] = {
469a9a302fSBernhard Schmidt [IEEE80211_RATECTL_AMRR] = "wlan_amrr",
479a9a302fSBernhard Schmidt [IEEE80211_RATECTL_RSSADAPT] = "wlan_rssadapt",
489a9a302fSBernhard Schmidt [IEEE80211_RATECTL_ONOE] = "wlan_onoe",
499a9a302fSBernhard Schmidt [IEEE80211_RATECTL_SAMPLE] = "wlan_sample",
509a9a302fSBernhard Schmidt [IEEE80211_RATECTL_NONE] = "wlan_none",
519a9a302fSBernhard Schmidt };
529a9a302fSBernhard Schmidt
53b6108616SRui Paulo MALLOC_DEFINE(M_80211_RATECTL, "80211ratectl", "802.11 rate control");
54b6108616SRui Paulo
55b6108616SRui Paulo void
ieee80211_ratectl_register(int type,const struct ieee80211_ratectl * ratectl)56b6108616SRui Paulo ieee80211_ratectl_register(int type, const struct ieee80211_ratectl *ratectl)
57b6108616SRui Paulo {
58b6108616SRui Paulo if (type >= IEEE80211_RATECTL_MAX)
59b6108616SRui Paulo return;
60b6108616SRui Paulo ratectls[type] = ratectl;
61b6108616SRui Paulo }
62b6108616SRui Paulo
63b6108616SRui Paulo void
ieee80211_ratectl_unregister(int type)64b6108616SRui Paulo ieee80211_ratectl_unregister(int type)
65b6108616SRui Paulo {
66b6108616SRui Paulo if (type >= IEEE80211_RATECTL_MAX)
67b6108616SRui Paulo return;
68b6108616SRui Paulo ratectls[type] = NULL;
69b6108616SRui Paulo }
70b6108616SRui Paulo
7173931706SAdrian Chadd static void
ieee80211_ratectl_sysctl_stats_node_iter(void * arg,struct ieee80211_node * ni)7273931706SAdrian Chadd ieee80211_ratectl_sysctl_stats_node_iter(void *arg, struct ieee80211_node *ni)
7373931706SAdrian Chadd {
7473931706SAdrian Chadd
7573931706SAdrian Chadd struct sbuf *sb = (struct sbuf *) arg;
7673931706SAdrian Chadd sbuf_printf(sb, "MAC: %6D\n", ni->ni_macaddr, ":");
7773931706SAdrian Chadd ieee80211_ratectl_node_stats(ni, sb);
7873931706SAdrian Chadd sbuf_printf(sb, "\n");
7973931706SAdrian Chadd }
8073931706SAdrian Chadd
8173931706SAdrian Chadd static int
ieee80211_ratectl_sysctl_stats(SYSCTL_HANDLER_ARGS)8273931706SAdrian Chadd ieee80211_ratectl_sysctl_stats(SYSCTL_HANDLER_ARGS)
8373931706SAdrian Chadd {
8473931706SAdrian Chadd struct ieee80211vap *vap = arg1;
8573931706SAdrian Chadd struct ieee80211com *ic = vap->iv_ic;
8673931706SAdrian Chadd struct sbuf sb;
8773931706SAdrian Chadd int error;
8873931706SAdrian Chadd
8973931706SAdrian Chadd error = sysctl_wire_old_buffer(req, 0);
9073931706SAdrian Chadd if (error)
9173931706SAdrian Chadd return (error);
9273931706SAdrian Chadd sbuf_new_for_sysctl(&sb, NULL, 8, req);
9373931706SAdrian Chadd sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
9473931706SAdrian Chadd
9573931706SAdrian Chadd IEEE80211_LOCK(ic);
9673931706SAdrian Chadd ieee80211_iterate_nodes(&ic->ic_sta,
9773931706SAdrian Chadd ieee80211_ratectl_sysctl_stats_node_iter,
9873931706SAdrian Chadd &sb);
9973931706SAdrian Chadd IEEE80211_UNLOCK(ic);
10073931706SAdrian Chadd
10173931706SAdrian Chadd error = sbuf_finish(&sb);
10273931706SAdrian Chadd sbuf_delete(&sb);
10373931706SAdrian Chadd return (error);
10473931706SAdrian Chadd }
10573931706SAdrian Chadd
106b6108616SRui Paulo void
ieee80211_ratectl_init(struct ieee80211vap * vap)107a7c6aabdSBernhard Schmidt ieee80211_ratectl_init(struct ieee80211vap *vap)
108a7c6aabdSBernhard Schmidt {
109a7c6aabdSBernhard Schmidt if (vap->iv_rate == ratectls[IEEE80211_RATECTL_NONE])
110a7c6aabdSBernhard Schmidt ieee80211_ratectl_set(vap, IEEE80211_RATECTL_AMRR);
111a7c6aabdSBernhard Schmidt vap->iv_rate->ir_init(vap);
11273931706SAdrian Chadd
11373931706SAdrian Chadd /* Attach generic stats sysctl */
11473931706SAdrian Chadd SYSCTL_ADD_PROC(vap->iv_sysctl, SYSCTL_CHILDREN(vap->iv_oid), OID_AUTO,
11573931706SAdrian Chadd "rate_stats", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, vap,
11673931706SAdrian Chadd 0, ieee80211_ratectl_sysctl_stats, "A", "ratectl node stats");
117a7c6aabdSBernhard Schmidt }
118a7c6aabdSBernhard Schmidt
119a7c6aabdSBernhard Schmidt void
ieee80211_ratectl_set(struct ieee80211vap * vap,int type)120b6108616SRui Paulo ieee80211_ratectl_set(struct ieee80211vap *vap, int type)
121b6108616SRui Paulo {
122b6108616SRui Paulo if (type >= IEEE80211_RATECTL_MAX)
123b6108616SRui Paulo return;
1249a9a302fSBernhard Schmidt if (ratectls[type] == NULL) {
1259a9a302fSBernhard Schmidt ieee80211_load_module(ratectl_modnames[type]);
1269a9a302fSBernhard Schmidt if (ratectls[type] == NULL) {
1279a9a302fSBernhard Schmidt IEEE80211_DPRINTF(vap, IEEE80211_MSG_RATECTL,
1289a9a302fSBernhard Schmidt "%s: unable to load algo %u, module %s\n",
1299a9a302fSBernhard Schmidt __func__, type, ratectl_modnames[type]);
1309a9a302fSBernhard Schmidt vap->iv_rate = ratectls[IEEE80211_RATECTL_NONE];
1319a9a302fSBernhard Schmidt return;
1329a9a302fSBernhard Schmidt }
1339a9a302fSBernhard Schmidt }
134b6108616SRui Paulo vap->iv_rate = ratectls[type];
135b6108616SRui Paulo }
136