1 /* $OpenBSD: ieee80211_amrr.c,v 1.12 2019/02/24 09:36:28 stsp Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 5 * Damien Bergamini <damien.bergamini@free.fr> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/kernel.h> 23 #include <sys/socket.h> 24 25 #include <net/if.h> 26 #include <net/if_media.h> 27 28 #include <netinet/in.h> 29 #include <netinet/if_ether.h> 30 31 #include <net80211/ieee80211_var.h> 32 #include <net80211/ieee80211_priv.h> 33 #include <net80211/ieee80211_amrr.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 reset_cnt(amn) \ 42 do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0) 43 44 static inline int 45 is_min_rate(struct ieee80211_node *ni) 46 { 47 return (ni->ni_txrate == 0); 48 } 49 50 static inline int 51 is_max_rate(struct ieee80211_node *ni) 52 { 53 return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1); 54 } 55 56 static inline void 57 increase_rate(struct ieee80211_node *ni) 58 { 59 ni->ni_txrate++; 60 } 61 62 static inline void 63 decrease_rate(struct ieee80211_node *ni) 64 { 65 ni->ni_txrate--; 66 } 67 68 void 69 ieee80211_amrr_node_init(const struct ieee80211_amrr *amrr, 70 struct ieee80211_amrr_node *amn) 71 { 72 amn->amn_success = 0; 73 amn->amn_recovery = 0; 74 amn->amn_txcnt = amn->amn_retrycnt = 0; 75 amn->amn_success_threshold = amrr->amrr_min_success_threshold; 76 } 77 78 /* 79 * Update ni->ni_txrate. 80 */ 81 void 82 ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni, 83 struct ieee80211_amrr_node *amn) 84 { 85 #define RV(rate) ((rate) & IEEE80211_RATE_VAL) 86 int need_change = 0; 87 88 if (is_success(amn) && is_enough(amn)) { 89 amn->amn_success++; 90 if (amn->amn_success >= amn->amn_success_threshold && 91 !is_max_rate(ni)) { 92 amn->amn_recovery = 1; 93 amn->amn_success = 0; 94 increase_rate(ni); 95 DPRINTF(("increase rate=%d,#tx=%d,#retries=%d\n", 96 RV(ni->ni_rates.rs_rates[ni->ni_txrate]), 97 amn->amn_txcnt, amn->amn_retrycnt)); 98 need_change = 1; 99 } else { 100 amn->amn_recovery = 0; 101 } 102 } else if (is_failure(amn)) { 103 amn->amn_success = 0; 104 if (!is_min_rate(ni)) { 105 if (amn->amn_recovery) { 106 amn->amn_success_threshold *= 2; 107 if (amn->amn_success_threshold > 108 amrr->amrr_max_success_threshold) 109 amn->amn_success_threshold = 110 amrr->amrr_max_success_threshold; 111 } else { 112 amn->amn_success_threshold = 113 amrr->amrr_min_success_threshold; 114 } 115 decrease_rate(ni); 116 DPRINTF(("decrease rate=%d,#tx=%d,#retries=%d\n", 117 RV(ni->ni_rates.rs_rates[ni->ni_txrate]), 118 amn->amn_txcnt, amn->amn_retrycnt)); 119 need_change = 1; 120 } 121 amn->amn_recovery = 0; 122 } 123 124 if (is_enough(amn) || need_change) 125 reset_cnt(amn); 126 #undef RV 127 } 128