1 /*
2  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_ratectl.c,v 1.4 2007/04/01 13:59:41 sephe Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 
40 #include <net/if.h>
41 #include <net/if_media.h>
42 #include <net/if_arp.h>
43 
44 #include <netproto/802_11/ieee80211_var.h>
45 
46 static const struct ieee80211_ratectl *ratectls[IEEE80211_RATECTL_MAX] = {
47 	[IEEE80211_RATECTL_NONE]	= &ieee80211_ratectl_none
48 };
49 
50 static const char *ratectl_modname[IEEE80211_RATECTL_MAX] = {
51 	[IEEE80211_RATECTL_ONOE]	= "wlan_ratectl_onoe",
52 	[IEEE80211_RATECTL_AMRR]	= "wlan_ratectl_amrr",
53 	[IEEE80211_RATECTL_SAMPLE]	= "wlan_ratectl_sample"
54 };
55 
56 void
57 ieee80211_ratectl_attach(struct ieee80211com *ic)
58 {
59 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
60 	u_int cur_ratectl = rc_st->rc_st_ratectl;
61 
62 	rc_st->rc_st_ratectl_cap |= IEEE80211_RATECTL_CAP_NONE;
63 	rc_st->rc_st_ratectl = IEEE80211_RATECTL_NONE;
64 
65 	ieee80211_ratectl_change(ic, cur_ratectl);
66 }
67 
68 void
69 ieee80211_ratectl_detach(struct ieee80211com *ic)
70 {
71 	ieee80211_ratectl_change(ic, IEEE80211_RATECTL_NONE);
72 }
73 
74 void
75 ieee80211_ratectl_register(const struct ieee80211_ratectl *rc)
76 {
77 	/*
78 	 * Sanity checks
79 	 */
80 	if (rc->rc_ratectl >= IEEE80211_RATECTL_MAX) {
81 		kprintf("%s: rate control %s has an invalid index %d\n",
82 		       __func__, rc->rc_name, rc->rc_ratectl);
83 		return;
84 	}
85 	if (ratectls[rc->rc_ratectl] != NULL &&
86 	    ratectls[rc->rc_ratectl] != rc) {
87 		kprintf("%s: rate control index %d is registered by %s\n",
88 		       __func__, rc->rc_ratectl,
89 		       ratectls[rc->rc_ratectl]->rc_name);
90 		return;
91 	}
92 
93 	ratectls[rc->rc_ratectl] = rc;
94 }
95 
96 void
97 ieee80211_ratectl_unregister(const struct ieee80211_ratectl *rc)
98 {
99 	/*
100 	 * Sanity checks
101 	 */
102 	if (rc->rc_ratectl >= IEEE80211_RATECTL_MAX) {
103 		kprintf("%s: rate control %s has an invalid index %d\n",
104 		       __func__, rc->rc_name, rc->rc_ratectl);
105 		return;
106 	}
107 	if (ratectls[rc->rc_ratectl] != NULL &&
108 	    ratectls[rc->rc_ratectl] != rc) {
109 		kprintf("%s: rate control index %d is registered by %s\n",
110 		       __func__, rc->rc_ratectl,
111 		       ratectls[rc->rc_ratectl]->rc_name);
112 		return;
113 	}
114 
115 	/*
116 	 * Indiviual rate control module MUST maintain reference count itself.
117 	 */
118 	ratectls[rc->rc_ratectl] = NULL;
119 }
120 
121 int
122 ieee80211_ratectl_change(struct ieee80211com *ic, u_int rc_idx)
123 {
124 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
125 	const struct ieee80211_ratectl *rc, *rc_old;
126 
127 	if (rc_idx == rc_st->rc_st_ratectl) {
128 		/* Nothing need to be changed */
129 		return 0;
130 	}
131 
132 	if ((IEEE80211_RATECTL_CAP(rc_idx) & rc_st->rc_st_ratectl_cap) == 0) {
133 		/* We are not capable to do requested rate control */
134 		return EOPNOTSUPP;
135 	}
136 
137 	rc = ratectls[rc_idx];
138 	if (rc == NULL) {
139 		/* Try load the rate control module */
140 		ieee80211_load_module(ratectl_modname[rc_idx]);
141 
142 		/*
143 		 * If rate control module loaded it should immediately
144 		 * call ieee80211_ratectl_register() which will fill in
145 		 * the entry in the 'ratectls' array.
146 		 */
147 		rc = ratectls[rc_idx];
148 		if (rc == NULL) {
149 			kprintf("%s: can't load requested rate control module",
150 			       __func__);
151 			return EOPNOTSUPP;
152 		}
153 	}
154 
155 	/* Detach old rate control */
156 	rc_old = ratectls[rc_st->rc_st_ratectl];
157 	rc_old->rc_detach(rc_st->rc_st_ctx);
158 
159 	if (rc_st->rc_st_change != NULL)
160 		rc_st->rc_st_change(ic, rc_st->rc_st_ratectl, rc_idx);
161 
162 	/* Attach new rate control */
163 	rc_st->rc_st_ratectl = rc_idx;
164 	rc_st->rc_st_ctx = rc->rc_attach(ic);
165 
166 	return 0;
167 }
168 
169 void
170 ieee80211_ratectl_data_alloc(struct ieee80211_node *ni)
171 {
172 	struct ieee80211com *ic = ni->ni_ic;
173 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
174 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
175 
176 	rc->rc_data_alloc(ni);
177 }
178 
179 void
180 ieee80211_ratectl_data_dup(const struct ieee80211_node *oni,
181 			   struct ieee80211_node *nni)
182 {
183 	struct ieee80211com *ic = oni->ni_ic;
184 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
185 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
186 
187 	rc->rc_data_dup(oni, nni);
188 }
189 
190 void
191 ieee80211_ratectl_data_free(struct ieee80211_node *ni)
192 {
193 	struct ieee80211com *ic = ni->ni_ic;
194 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
195 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
196 
197 	rc->rc_data_free(ni);
198 }
199 
200 void
201 ieee80211_ratectl_newstate(struct ieee80211com *ic, enum ieee80211_state state)
202 {
203 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
204 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
205 
206 	rc->rc_newstate(rc_st->rc_st_ctx, state);
207 }
208 
209 void
210 ieee80211_ratectl_tx_complete(struct ieee80211_node *ni, int frame_len,
211 			      const struct ieee80211_ratectl_res res[],
212 			      int res_len, int data_retries, int rts_retries,
213 			      int is_fail)
214 {
215 	struct ieee80211com *ic = ni->ni_ic;
216 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
217 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
218 
219 	rc->rc_tx_complete(rc_st->rc_st_ctx, ni, frame_len, res, res_len,
220 			   data_retries, rts_retries, is_fail);
221 }
222 
223 void
224 ieee80211_ratectl_newassoc(struct ieee80211_node *ni, int is_new)
225 {
226 	struct ieee80211com *ic = ni->ni_ic;
227 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
228 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
229 
230 	rc->rc_newassoc(rc_st->rc_st_ctx, ni, is_new);
231 }
232 
233 int
234 ieee80211_ratectl_findrate(struct ieee80211_node *ni, int frame_len,
235 			   int rateidx[], int rateidx_len)
236 {
237 	struct ieee80211com *ic = ni->ni_ic;
238 	struct ieee80211_ratectl_state *rc_st = &ic->ic_ratectl;
239 	const struct ieee80211_ratectl *rc = ratectls[rc_st->rc_st_ratectl];
240 
241 	KKASSERT(rateidx_len > 0);
242 
243 	return rc->rc_findrate(rc_st->rc_st_ctx, ni, frame_len,
244 			       rateidx, rateidx_len);
245 }
246