Do proper locking in the callout functions.
[dragonfly.git] / sys / netproto / 802_11 / wlan_ratectl / onoe / ieee80211_ratectl_onoe.c
1 /*
2  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  * 3. Neither the names of the above-listed copyright holders nor the names
16  *    of any contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * Alternatively, this software may be distributed under the terms of the
20  * GNU General Public License ("GPL") version 2 as published by the Free
21  * Software Foundation.
22  *
23  * NO WARRANTY
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34  * THE POSSIBILITY OF SUCH DAMAGES.
35  *
36  * $FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.c,v 1.8.2.3 2006/02/24 19:51:11 sam Exp $
37  * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c,v 1.10 2008/01/15 09:01:13 sephe Exp $
38  */
39
40 /*
41  * Atsushi Onoe's rate control algorithm.
42  */
43
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/sysctl.h>
49 #include <sys/serialize.h>
50  
51 #include <net/if.h>
52 #include <net/if_media.h>
53 #include <net/if_arp.h>
54
55 #include <netproto/802_11/ieee80211_var.h>
56 #include <netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h>
57
58 #define ONOE_DEBUG
59
60 #ifdef ONOE_DEBUG
61 #define DPRINTF(osc, lv, fmt, ...) do {         \
62         if ((osc)->param->onoe_debug >= lv)     \
63                 kprintf(fmt, __VA_ARGS__);      \
64 } while (0)
65 #else
66 #define DPRINTF(osc, lv, fmt, ...)
67 #endif
68
69 struct onoe_softc {
70         struct ieee80211vap     *vap;
71         struct callout          timer;          /* periodic timer */
72
73         struct sysctl_ctx_list  sysctl_ctx;
74         struct sysctl_oid       *sysctl_oid;
75
76         struct ieee80211_onoe_param *param;
77 #define raise           param->onoe_raise
78 #define raise_threshold param->onoe_raise_threshold
79 };
80
81 struct onoe_data {
82         u_int           od_tx_ok;       /* tx ok pkt */
83         u_int           od_tx_err;      /* tx !ok pkt */
84         u_int           od_tx_retr;     /* tx retry count */
85         int             od_tx_upper;    /* tx upper rate req cnt */
86 };
87
88 /*
89  * Default parameters for the rate control algorithm.  These are
90  * all tunable with sysctls.  The rate controller runs periodically
91  * (each ath_rateinterval ms) analyzing transmit statistics for each
92  * neighbor/station (when operating in station mode this is only the AP).
93  * If transmits look to be working well over a sampling period then
94  * it gives a "raise rate credit".  If transmits look to not be working
95  * well than it deducts a credit.  If the credits cross a threshold then
96  * the transmit rate is raised.  Various error conditions force the
97  * the transmit rate to be dropped.
98  *
99  * The decision to issue/deduct a credit is based on the errors and
100  * retries accumulated over the sampling period.  ath_rate_raise defines
101  * the percent of retransmits for which a credit is issued/deducted.
102  * ath_rate_raise_threshold defines the threshold on credits at which
103  * the transmit rate is increased.
104  *
105  * XXX this algorithm is flawed.
106  */
107
108 static void     *onoe_attach(struct ieee80211vap *);
109 static void     onoe_detach(void *);
110 static void     onoe_data_free(struct ieee80211_node *);
111 static void     onoe_data_alloc(struct ieee80211_node *);
112 static void     onoe_data_dup(const struct ieee80211_node *,
113                               struct ieee80211_node *);
114 static void     onoe_newstate(void *, enum ieee80211_state);
115 static void     onoe_tx_complete(void *, struct ieee80211_node *, int,
116                                  const struct ieee80211_ratectl_res[],
117                                  int, int, int, int);
118 static void     onoe_newassoc(void *, struct ieee80211_node *, int);
119 static int      onoe_findrate(void *, struct ieee80211_node *, int,
120                               int[], int);
121
122 static void     onoe_sysctl_attach(struct onoe_softc *);
123 static void     onoe_update(struct onoe_softc *, struct ieee80211_node *, int);
124 static void     onoe_start(struct onoe_softc *, struct ieee80211_node *);
125 static void     onoe_tick(void *);
126 static void     onoe_ratectl(void *, struct ieee80211_node *);
127 static void     onoe_gather_stats(struct onoe_softc *, struct ieee80211_node *);
128
129 static const struct ieee80211_ratectl onoe = {
130         .rc_name        = "onoe",
131         .rc_ratectl     = IEEE80211_RATECTL_ONOE,
132         .rc_attach      = onoe_attach,
133         .rc_detach      = onoe_detach,
134         .rc_data_alloc  = onoe_data_alloc,
135         .rc_data_free   = onoe_data_free,
136         .rc_data_dup    = onoe_data_dup,
137         .rc_newstate    = onoe_newstate,
138         .rc_tx_complete = onoe_tx_complete,
139         .rc_newassoc    = onoe_newassoc,
140         .rc_findrate    = onoe_findrate
141 };
142
143 static u_int    onoe_nrefs;
144
145 MALLOC_DEFINE(M_ONOE_RATECTL_DATA, "onoe_ratectl_data",
146               "onoe rate control data");
147
148 static void
149 onoe_tx_complete(void *arg __unused, struct ieee80211_node *ni,
150                  int frame_len __unused,
151                  const struct ieee80211_ratectl_res res[] __unused,
152                  int res_len __unused,
153                  int data_retries, int rts_retries __unused, int is_fail)
154 {
155         struct onoe_data *od = ni->ni_rate_data;
156
157         if (od == NULL)
158                 return;
159
160         if (is_fail)
161                 od->od_tx_err++;
162         else
163                 od->od_tx_ok++;
164
165         od->od_tx_retr += data_retries;
166 }
167
168 static void
169 onoe_newassoc(void *arg, struct ieee80211_node *ni, int is_new)
170 {
171         if (is_new)
172                 onoe_start(arg, ni);
173 }
174
175 static int
176 onoe_findrate(void *arg, struct ieee80211_node *ni,
177               int frame_len __unused, int rateidx[], int rateidx_len)
178 {
179         struct onoe_softc *osc = arg;
180         int i, rate_idx;
181
182         if (ni->ni_txrate >= ni->ni_rates.rs_nrates) {
183                 DPRINTF(osc, 5, "%s: number of rates changed, restart\n",
184                         __func__);
185                 onoe_start(osc, ni);
186         }
187         rate_idx = ni->ni_txrate;
188
189         for (i = 0; i < rateidx_len; ++i) {
190                 if (rate_idx < 0)
191                         break;
192                 rateidx[i] = rate_idx--;
193         }
194         if (rateidx_len > 1)
195                 rateidx[rateidx_len - 1] = 0;
196         return i;
197 }
198
199 static void
200 onoe_update(struct onoe_softc *osc, struct ieee80211_node *ni, int nrate)
201 {
202         struct onoe_data *od = ni->ni_rate_data;
203
204         DPRINTF(osc, 1, "%s: set xmit rate for %6D to %dM\n", __func__,
205                 ni->ni_macaddr, ":",
206                 ni->ni_rates.rs_nrates > 0 ?
207                 IEEE80211_RS_RATE(&ni->ni_rates, nrate) / 2 : 0);
208
209         ni->ni_txrate = nrate;
210
211         if (od == NULL) {
212                 onoe_data_alloc(ni);
213         } else {
214                 od->od_tx_ok = 0;
215                 od->od_tx_err = 0;
216                 od->od_tx_retr = 0;
217                 od->od_tx_upper = 0;
218         }
219 }
220
221 /*
222  * Set the starting transmit rate for a node.
223  */
224 static void
225 onoe_start(struct onoe_softc *osc, struct ieee80211_node *ni)
226 {
227 #define RATE(_ix)       IEEE80211_RS_RATE(&ni->ni_rates, (_ix))
228         struct ieee80211vap *vap = osc->vap;
229         int srate;
230         const struct ieee80211_txparam *tp = ni->ni_txparms;
231         enum ieee80211_phymode mode =
232             ieee80211_chan2mode(vap->iv_ic->ic_curchan);
233
234         KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates"));
235         if (tp == NULL || tp->ucastrate == IEEE80211_FIXED_RATE_NONE) {
236                 /*
237                  * For adhoc or ibss mode, start from the lowest rate.
238                  */
239                 if (vap->iv_opmode == IEEE80211_M_AHDEMO ||
240                     vap->iv_opmode == IEEE80211_M_IBSS) {
241                         onoe_update(osc, ni, 0);
242                         return;
243                 }
244
245                 /*
246                  * No fixed rate is requested. For 11b start with
247                  * the highest negotiated rate; otherwise, for 11g
248                  * and 11a, we start "in the middle" at 24Mb or 36Mb.
249                  */
250                 srate = ni->ni_rates.rs_nrates - 1;
251                 if (mode != IEEE80211_MODE_11B) {
252                         /*
253                          * Scan the negotiated rate set to find the
254                          * closest rate.
255                          */
256                         /* NB: the rate set is assumed sorted */
257                         for (; srate >= 0 && RATE(srate) > 72; srate--)
258                                 ;
259                         KASSERT(srate >= 0, ("bogus rate set"));
260                 }
261         } else {
262                 /*
263                  * A fixed rate is to be used; ucastrate is an
264                  * index into the supported rate set.  Convert this
265                  * to the index into the negotiated rate set for
266                  * the node.  We know the rate is there because the
267                  * rate set is checked when the station associates.
268                  */
269                 const struct ieee80211_rateset *rs =
270                         &vap->iv_ic->ic_sup_rates[vap->iv_ic->ic_curmode];
271                 int r = IEEE80211_RS_RATE(rs, vap->iv_txparms[mode].ucastrate);
272
273                 /* NB: the rate set is assumed sorted */
274                 srate = ni->ni_rates.rs_nrates - 1;
275                 for (; srate >= 0 && RATE(srate) != r; srate--)
276                         ;
277                 KASSERT(srate >= 0,
278                         ("fixed rate %d not in rate set", tp->ucastrate));
279         }
280         onoe_update(osc, ni, srate);
281 #undef RATE
282 }
283
284 static void
285 onoe_rate_cb(void *arg, struct ieee80211_node *ni)
286 {
287         onoe_update(arg, ni, 0);
288 }
289
290 static void
291 onoe_newstate(void *arg, enum ieee80211_state state)
292 {
293         struct onoe_softc *osc = arg;
294         struct ieee80211vap *vap = osc->vap;
295         struct ieee80211_node *ni;
296         const struct ieee80211_txparam *tp = NULL;
297
298         if (state == IEEE80211_S_INIT) {
299                 callout_stop(&osc->timer);
300                 return;
301         }
302
303         if (vap->iv_opmode == IEEE80211_M_STA) {
304                 /*
305                  * Reset local xmit state; this is really only
306                  * meaningful when operating in station mode.
307                  */
308                 ni = vap->iv_bss;
309                 tp = ni->ni_txparms;
310                 if (state == IEEE80211_S_RUN)
311                         onoe_start(osc, ni);
312                 else
313                         onoe_update(osc, ni, 0);
314         } else {
315                 /*
316                  * When operating as a station the node table holds
317                  * the AP's that were discovered during scanning.
318                  * For any other operating mode we want to reset the
319                  * tx rate state of each node.
320                  */
321                 ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, onoe_rate_cb, osc);
322                 onoe_update(osc, vap->iv_bss, 0);
323         }
324
325         if ((tp == NULL || tp->ucastrate == IEEE80211_FIXED_RATE_NONE) &&
326             state == IEEE80211_S_RUN) {
327                 int interval;
328
329                 /*
330                  * Start the background rate control thread if we
331                  * are not configured to use a fixed xmit rate.
332                  */
333                 interval = osc->param->onoe_interval;
334                 if (vap->iv_opmode == IEEE80211_M_STA)
335                         interval /= 2;
336                 callout_reset(&osc->timer, (interval * hz) / 1000,
337                               onoe_tick, osc);
338         }
339 }
340
341 static void
342 onoe_gather_stats(struct onoe_softc *osc, struct ieee80211_node *ni)
343 {
344         struct onoe_data *od = ni->ni_rate_data;
345         struct ieee80211vap *vap = osc->vap;
346         const struct ieee80211_ratectl_state *st = &vap->iv_ratectl;
347         struct ieee80211_ratectl_stats stats;
348
349         st->rc_st_stats(vap, ni, &stats);
350
351         od->od_tx_ok += stats.stats_pkt_ok;
352         od->od_tx_err += stats.stats_pkt_err;
353         od->od_tx_retr += stats.stats_retries;
354 }
355
356 static void
357 onoe_ratectl(void *arg, struct ieee80211_node *ni)
358 {
359         struct onoe_softc *osc = arg;
360         struct onoe_data *od = ni->ni_rate_data;
361         const struct ieee80211_ratectl_state *st = &osc->vap->iv_ratectl;
362         struct ieee80211_rateset *rs = &ni->ni_rates;
363         int dir = 0, nrate, enough;
364
365         if (od == NULL) {
366                 /* We are no ready to go, set TX rate to lowest one */
367                 ni->ni_txrate = 0;
368                 return;
369         }
370
371         if (st->rc_st_stats != NULL)
372                 onoe_gather_stats(osc, ni);
373
374         /*
375          * Rate control
376          * XXX: very primitive version.
377          */
378         enough = (od->od_tx_ok + od->od_tx_err >= 10);
379
380         /* no packet reached -> down */
381         if (od->od_tx_err > 0 && od->od_tx_ok == 0)
382                 dir = -1;
383
384         /* all packets needs retry in average -> down */
385         if (enough && od->od_tx_ok < od->od_tx_retr)
386                 dir = -1;
387
388         /* no error and less than rate_raise% of packets need retry -> up */
389         if (enough && od->od_tx_err == 0 &&
390             od->od_tx_retr < (od->od_tx_ok * osc->raise) / 100)
391                 dir = 1;
392
393         DPRINTF(osc, 10, "%6D: ok %d err %d retr %d upper %d dir %d\n",
394                 ni->ni_macaddr, ":",
395                 od->od_tx_ok, od->od_tx_err, od->od_tx_retr,
396                 od->od_tx_upper, dir);
397
398         nrate = ni->ni_txrate;
399         switch (dir) {
400         case 0:
401                 if (enough && od->od_tx_upper > 0)
402                         od->od_tx_upper--;
403                 break;
404         case -1:
405                 if (nrate > 0)
406                         nrate--;
407                 od->od_tx_upper = 0;
408                 break;
409         case 1:
410                 /* raise rate if we hit rate_raise_threshold */
411                 if (++od->od_tx_upper < osc->raise_threshold)
412                         break;
413                 od->od_tx_upper = 0;
414                 if (nrate + 1 < rs->rs_nrates)
415                         nrate++;
416                 break;
417         }
418
419         if (nrate != ni->ni_txrate) {
420                 DPRINTF(osc, 5, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n",
421                         __func__,
422                         IEEE80211_RS_RATE(rs, ni->ni_txrate) / 2,
423                         IEEE80211_RS_RATE(rs, nrate) / 2,
424                         od->od_tx_ok, od->od_tx_err, od->od_tx_retr);
425                 onoe_update(osc, ni, nrate);
426         } else if (enough) {
427                 od->od_tx_ok = od->od_tx_err = od->od_tx_retr = 0;
428         }
429 }
430
431 static void
432 onoe_tick(void *arg)
433 {
434         struct onoe_softc *osc = arg;
435         struct ieee80211vap *vap = osc->vap;
436         struct ifnet *ifp = vap->iv_ifp;
437         int interval;
438
439         ifnet_serialize_all(ifp);
440
441         if (ifp->if_flags & IFF_RUNNING) {
442                 if (vap->iv_opmode == IEEE80211_M_STA)
443                         onoe_ratectl(osc, vap->iv_bss); /* NB: no reference */
444                 else
445                         ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, onoe_ratectl, osc);
446         }
447
448         interval = osc->param->onoe_interval;
449         if (vap->iv_opmode == IEEE80211_M_STA)
450                 interval /= 2;
451         callout_reset(&osc->timer, (interval * hz) / 1000, onoe_tick, osc);
452
453         ifnet_deserialize_all(ifp);
454 }
455
456 static void
457 onoe_sysctl_attach(struct onoe_softc *osc)
458 {
459         sysctl_ctx_init(&osc->sysctl_ctx);
460         osc->sysctl_oid = SYSCTL_ADD_NODE(&osc->sysctl_ctx,
461                 SYSCTL_CHILDREN(osc->vap->iv_oid),
462                 OID_AUTO, "onoe_ratectl", CTLFLAG_RD, 0, "");
463         if (osc->sysctl_oid == NULL) {
464                 kprintf("wlan_ratectl_onoe: create sysctl tree failed\n");
465                 return;
466         }
467
468         SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid),
469                        OID_AUTO, "interval", CTLFLAG_RW,
470                        &osc->param->onoe_interval, 0,
471                        "rate control: operation interval (ms)");
472
473         /* XXX bounds check values */
474         SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid),
475                        OID_AUTO, "raise", CTLFLAG_RW,
476                        &osc->param->onoe_raise, 0,
477                        "rate control: "
478                        "retry threshold to credit rate raise (%%)");
479
480         SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid),
481                        OID_AUTO, "raise_threshold", CTLFLAG_RW,
482                        &osc->param->onoe_raise_threshold, 0,
483                        "rate control: # good periods before raising rate");
484
485         SYSCTL_ADD_INT(&osc->sysctl_ctx, SYSCTL_CHILDREN(osc->sysctl_oid),
486                        OID_AUTO, "debug", CTLFLAG_RW,
487                        &osc->param->onoe_debug, 0,
488                        "rate control: debug level");
489 }
490
491 static void *
492 onoe_attach(struct ieee80211vap *vap)
493 {
494         struct onoe_softc *osc;
495
496         onoe_nrefs++;
497
498         osc = kmalloc(sizeof(struct onoe_softc), M_DEVBUF, M_WAITOK | M_ZERO);
499
500         osc->vap = vap;
501         callout_init(&osc->timer);
502         osc->param = vap->iv_ratectl.rc_st_attach(vap, IEEE80211_RATECTL_ONOE);
503
504         onoe_sysctl_attach(osc);
505
506         onoe_newstate(osc, vap->iv_state);
507
508         return osc;
509 }
510
511 static void
512 _onoe_data_free(void *arg __unused, struct ieee80211_node *ni)
513 {
514         onoe_data_free(ni);
515 }
516
517 static void
518 onoe_detach(void *arg)
519 {
520         struct onoe_softc *osc = arg;
521         struct ieee80211vap *vap = osc->vap;
522
523         onoe_newstate(osc, IEEE80211_S_INIT);
524
525         ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, _onoe_data_free, NULL);
526
527         if (osc->sysctl_oid != NULL)
528                 sysctl_ctx_free(&osc->sysctl_ctx);
529         kfree(osc, M_DEVBUF);
530
531         onoe_nrefs--;
532 }
533
534 static void
535 onoe_data_free(struct ieee80211_node *ni)
536 {
537         if (ni->ni_rate_data != NULL) {
538                 kfree(ni->ni_rate_data, M_ONOE_RATECTL_DATA);
539                 ni->ni_rate_data = NULL;
540         }
541 }
542
543 static void
544 onoe_data_alloc(struct ieee80211_node *ni)
545 {
546         KKASSERT(ni->ni_rate_data == NULL);
547         ni->ni_rate_data = kmalloc(sizeof(struct onoe_data),
548                                   M_ONOE_RATECTL_DATA, M_NOWAIT | M_ZERO);
549 }
550
551 static void
552 onoe_data_dup(const struct ieee80211_node *oni, struct ieee80211_node *nni)
553 {
554         if (oni->ni_rate_data == NULL || nni->ni_rate_data == NULL)
555                 return;
556
557         bcopy(oni->ni_rate_data, nni->ni_rate_data, sizeof(struct onoe_data));
558 }
559
560 static int
561 onoe_modevent(module_t mod, int type, void *unused)
562 {
563         switch (type) {
564         case MOD_LOAD:
565                 ieee80211_ratectl_register(&onoe);
566                 return 0;
567         case MOD_UNLOAD:
568                 if (onoe_nrefs) {
569                         kprintf("wlan_ratectl_onoe: still in use "
570                                "(%u dynamic refs)\n", onoe_nrefs);
571                         return EBUSY;
572                 }
573                 ieee80211_ratectl_unregister(&onoe);
574                 return 0;
575         }
576         return EINVAL;
577 }
578
579 static moduledata_t onoe_mod = {
580         "wlan_ratectl_onoe",
581         onoe_modevent,
582         0
583 };
584 DECLARE_MODULE(wlan_ratectl_onoe, onoe_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
585 MODULE_VERSION(wlan_ratectl_onoe, 1);
586 MODULE_DEPEND(wlan_ratectl_onoe, wlan, 1, 1, 1);