1 /* $NetBSD: ieee80211_amrr.c,v 1.2 2007/12/11 12:40:10 lukem Exp $ */ 2 /* $OpenBSD: ieee80211_amrr.c,v 1.1 2006/06/17 19:07:19 damien Exp $ */ 3 4 /* 5 * Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> 6 */ 7 8 /* 9 * Copyright (c) 2006 10 * Damien Bergamini <damien.bergamini@free.fr> 11 * 12 * Permission to use, copy, modify, and distribute this software for any 13 * purpose with or without fee is hereby granted, provided that the above 14 * copyright notice and this permission notice appear in all copies. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/socket.h> 27 #include <sys/sdt.h> 28 29 #include <net/if.h> 30 31 #include <sys/net80211.h> 32 #include <sys/net80211_amrr.h> 33 #include "net80211_impl.h" 34 35 #define is_success(amn) \ 36 ((amn)->amn_retrycnt < (amn)->amn_txcnt / 10) 37 #define is_failure(amn) \ 38 ((amn)->amn_retrycnt > (amn)->amn_txcnt / 3) 39 #define is_enough(amn) \ 40 ((amn)->amn_txcnt > 10) 41 #define is_min_rate(ni) \ 42 ((ni)->in_txrate == 0) 43 #define is_max_rate(ni) \ 44 ((ni)->in_txrate == (ni)->in_rates.ir_nrates - 1) 45 #define increase_rate(ni) \ 46 ((ni)->in_txrate++) 47 #define decrease_rate(ni) \ 48 ((ni)->in_txrate--) 49 #define reset_cnt(amn) \ 50 do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; \ 51 _NOTE(CONSTCOND) } while (0) 52 53 void 54 ieee80211_amrr_node_init(struct ieee80211_amrr *amrr, 55 struct ieee80211_amrr_node *amn) 56 { 57 amn->amn_success = 0; 58 amn->amn_recovery = 0; 59 amn->amn_txcnt = amn->amn_retrycnt = 0; 60 amn->amn_success_threshold = amrr->amrr_min_success_threshold; 61 } 62 63 /* 64 * Update ni->in_txrate. 65 */ 66 void 67 ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni, 68 struct ieee80211_amrr_node *amn) 69 { 70 int need_change = 0; 71 uint8_t rate; 72 73 if (is_success(amn) && is_enough(amn)) { 74 amn->amn_success++; 75 if (amn->amn_success >= amn->amn_success_threshold && 76 !is_max_rate(ni)) { 77 amn->amn_recovery = 1; 78 amn->amn_success = 0; 79 increase_rate(ni); 80 rate = ni->in_rates.ir_rates[ni->in_txrate] & 81 IEEE80211_RATE_VAL; 82 ieee80211_dbg(IEEE80211_MSG_XRATE, 83 "AMRR increasing rate %d (txcnt=%d retrycnt=%d)", 84 rate, amn->amn_txcnt, amn->amn_retrycnt); 85 DTRACE_PROBE4(amrr__increase__rate, 86 struct ieee80211_node *, ni, 87 uint8_t, rate, 88 uint_t, amn->amn_txcnt, 89 uint_t, amn->amn_retrycnt); 90 need_change = 1; 91 } else { 92 amn->amn_recovery = 0; 93 } 94 } else if (is_failure(amn)) { 95 amn->amn_success = 0; 96 if (!is_min_rate(ni)) { 97 if (amn->amn_recovery) { 98 amn->amn_success_threshold *= 2; 99 if (amn->amn_success_threshold > 100 amrr->amrr_max_success_threshold) 101 amn->amn_success_threshold = 102 amrr->amrr_max_success_threshold; 103 } else { 104 amn->amn_success_threshold = 105 amrr->amrr_min_success_threshold; 106 } 107 decrease_rate(ni); 108 rate = ni->in_rates.ir_rates[ni->in_txrate] & 109 IEEE80211_RATE_VAL; 110 ieee80211_dbg(IEEE80211_MSG_XRATE, 111 "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)", 112 rate, amn->amn_txcnt, amn->amn_retrycnt); 113 DTRACE_PROBE4(amrr__decrease__rate, 114 struct ieee80211_node *, ni, 115 uint8_t, rate, 116 uint_t, amn->amn_txcnt, 117 uint_t, amn->amn_retrycnt); 118 need_change = 1; 119 } 120 amn->amn_recovery = 0; 121 } 122 123 if (is_enough(amn) || need_change) 124 reset_cnt(amn); 125 } 126