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 44static inline int 45is_min_rate(struct ieee80211_node *ni) 46{ 47 return (ni->ni_txrate == 0); 48} 49 50static inline int 51is_max_rate(struct ieee80211_node *ni) 52{ 53 return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1); 54} 55 56static inline void 57increase_rate(struct ieee80211_node *ni) 58{ 59 ni->ni_txrate++; 60} 61 62static inline void 63decrease_rate(struct ieee80211_node *ni) 64{ 65 ni->ni_txrate--; 66} 67 68void 69ieee80211_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 */ 81void 82ieee80211_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