1 /* $OpenBSD: ieee80211_amrr.c,v 1.11 2016/01/05 18:41:16 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 /* 45 * XXX In HT mode we only support MCS 0-7, for now. 46 * Beyond MCS 7, incrementing the MCS index does not imply a 47 * higher data rate, so this simple implementation will need 48 * to be enhanced. 49 */ 50 51 static inline int 52 is_min_rate(struct ieee80211_node *ni) 53 { 54 if (ni->ni_flags & IEEE80211_NODE_HT) 55 return (ni->ni_txmcs == 0); 56 return (ni->ni_txrate == 0); 57 } 58 59 static inline int 60 is_max_rate(struct ieee80211_node *ni) 61 { 62 if (ni->ni_flags & IEEE80211_NODE_HT) 63 return (ni->ni_txmcs == 7); /* XXX up to MCS 7 only */ 64 return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1); 65 } 66 67 static inline void 68 increase_rate(struct ieee80211_node *ni) 69 { 70 if (ni->ni_flags & IEEE80211_NODE_HT) 71 ni->ni_txmcs++; 72 else 73 ni->ni_txrate++; 74 } 75 76 static inline void 77 decrease_rate(struct ieee80211_node *ni) 78 { 79 if (ni->ni_flags & IEEE80211_NODE_HT) 80 ni->ni_txmcs--; 81 else 82 ni->ni_txrate--; 83 } 84 85 void 86 ieee80211_amrr_node_init(const struct ieee80211_amrr *amrr, 87 struct ieee80211_amrr_node *amn) 88 { 89 amn->amn_success = 0; 90 amn->amn_recovery = 0; 91 amn->amn_txcnt = amn->amn_retrycnt = 0; 92 amn->amn_success_threshold = amrr->amrr_min_success_threshold; 93 } 94 95 /* 96 * Update ni->ni_txrate. 97 */ 98 void 99 ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni, 100 struct ieee80211_amrr_node *amn) 101 { 102 #define RV(rate) ((rate) & IEEE80211_RATE_VAL) 103 int need_change = 0; 104 105 if (is_success(amn) && is_enough(amn)) { 106 amn->amn_success++; 107 if (amn->amn_success >= amn->amn_success_threshold && 108 !is_max_rate(ni)) { 109 amn->amn_recovery = 1; 110 amn->amn_success = 0; 111 increase_rate(ni); 112 DPRINTF(("increase rate=%d,#tx=%d,#retries=%d\n", 113 (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs : 114 RV(ni->ni_rates.rs_rates[ni->ni_txrate]), 115 amn->amn_txcnt, amn->amn_retrycnt)); 116 need_change = 1; 117 } else { 118 amn->amn_recovery = 0; 119 } 120 } else if (is_failure(amn)) { 121 amn->amn_success = 0; 122 if (!is_min_rate(ni)) { 123 if (amn->amn_recovery) { 124 amn->amn_success_threshold *= 2; 125 if (amn->amn_success_threshold > 126 amrr->amrr_max_success_threshold) 127 amn->amn_success_threshold = 128 amrr->amrr_max_success_threshold; 129 } else { 130 amn->amn_success_threshold = 131 amrr->amrr_min_success_threshold; 132 } 133 decrease_rate(ni); 134 DPRINTF(("decrease rate=%d,#tx=%d,#retries=%d\n", 135 (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs : 136 RV(ni->ni_rates.rs_rates[ni->ni_txrate]), 137 amn->amn_txcnt, amn->amn_retrycnt)); 138 need_change = 1; 139 } 140 amn->amn_recovery = 0; 141 } 142 143 if (is_enough(amn) || need_change) 144 reset_cnt(amn); 145 #undef RV 146 } 147