1 /* $OpenBSD: ieee80211_rssadapt.c,v 1.11 2014/12/23 03:24:08 tedu Exp $ */ 2 /* $NetBSD: ieee80211_rssadapt.c,v 1.7 2004/05/25 04:33:59 dyoung Exp $ */ 3 4 /*- 5 * Copyright (c) 2003, 2004 David Young. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or 8 * without modification, are permitted provided that the following 9 * conditions are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials provided 15 * with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David 21 * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 28 * OF SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/socket.h> 35 36 #include <net/if.h> 37 #include <net/if_media.h> 38 39 #include <netinet/in.h> 40 #include <netinet/if_ether.h> 41 42 #include <net80211/ieee80211_var.h> 43 #include <net80211/ieee80211_rssadapt.h> 44 45 #ifdef interpolate 46 #undef interpolate 47 #endif 48 #define interpolate(parm, old, new) \ 49 ((parm##_old * (old) + \ 50 (parm##_denom - parm##_old) * (new)) / parm##_denom) 51 52 #ifdef IEEE80211_DEBUG 53 static struct timeval lastrateadapt; /* time of last rate adaptation msg */ 54 static int currssadaptps = 0; /* rate-adaptation msgs this second */ 55 static int ieee80211_adaptrate = 4; /* rate-adaptation max msgs/sec */ 56 57 #define RSSADAPT_DO_PRINT() \ 58 ((ieee80211_rssadapt_debug > 0) && \ 59 ppsratecheck(&lastrateadapt, &currssadaptps, ieee80211_adaptrate)) 60 #define RSSADAPT_PRINTF(X) \ 61 if (RSSADAPT_DO_PRINT()) \ 62 printf X 63 64 int ieee80211_rssadapt_debug = 0; 65 66 #else 67 #define RSSADAPT_DO_PRINT() (0) 68 #define RSSADAPT_PRINTF(X) 69 #endif 70 71 static const struct ieee80211_rssadapt_expavgctl master_expavgctl = { 72 .rc_decay_denom = 16, 73 .rc_decay_old = 15, 74 .rc_thresh_denom = 8, 75 .rc_thresh_old = 4, 76 .rc_avgrssi_denom = 8, 77 .rc_avgrssi_old = 4 78 }; 79 80 int 81 ieee80211_rssadapt_choose(struct ieee80211_rssadapt *ra, 82 const struct ieee80211_rateset *rs, const struct ieee80211_frame *wh, 83 u_int len, int fixed_rate, const char *dvname, int do_not_adapt) 84 { 85 u_int16_t (*thrs)[IEEE80211_RATE_SIZE]; 86 int flags = 0, i, rateidx = 0, thridx, top; 87 88 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 89 flags |= IEEE80211_RATE_BASIC; 90 91 for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 92 i < IEEE80211_RSSADAPT_BKTS; 93 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 94 thridx = i; 95 if (len <= top) 96 break; 97 } 98 99 thrs = &ra->ra_rate_thresh[thridx]; 100 101 if (fixed_rate != -1) { 102 if ((rs->rs_rates[fixed_rate] & flags) == flags) { 103 rateidx = fixed_rate; 104 goto out; 105 } 106 flags |= IEEE80211_RATE_BASIC; 107 i = fixed_rate; 108 } else 109 i = rs->rs_nrates; 110 111 while (--i >= 0) { 112 rateidx = i; 113 if ((rs->rs_rates[i] & flags) != flags) 114 continue; 115 if (do_not_adapt) 116 break; 117 if ((*thrs)[i] < ra->ra_avg_rssi) 118 break; 119 } 120 121 out: 122 #ifdef IEEE80211_DEBUG 123 if (ieee80211_rssadapt_debug && dvname != NULL) { 124 printf("%s: dst %s threshold[%d, %d.%d] %d < %d\n", 125 dvname, ether_sprintf((u_int8_t *)wh->i_addr1), len, 126 (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) / 2, 127 (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) * 5 % 10, 128 (*thrs)[rateidx], ra->ra_avg_rssi); 129 } 130 #endif /* IEEE80211_DEBUG */ 131 return rateidx; 132 } 133 134 void 135 ieee80211_rssadapt_updatestats(struct ieee80211_rssadapt *ra) 136 { 137 long interval; 138 139 ra->ra_pktrate = 140 (ra->ra_pktrate + 10 * (ra->ra_nfail + ra->ra_nok)) / 2; 141 ra->ra_nfail = ra->ra_nok = 0; 142 143 /* a node is eligible for its rate to be raised every 1/10 to 10 144 * seconds, more eligible in proportion to recent packet rates. 145 */ 146 interval = MAX(100000, 10000000 / MAX(1, 10 * ra->ra_pktrate)); 147 ra->ra_raise_interval.tv_sec = interval / (1000 * 1000); 148 ra->ra_raise_interval.tv_usec = interval % (1000 * 1000); 149 } 150 151 void 152 ieee80211_rssadapt_input(struct ieee80211com *ic, 153 const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, int rssi) 154 { 155 #ifdef IEEE80211_DEBUG 156 int last_avg_rssi = ra->ra_avg_rssi; 157 #endif 158 159 ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi, 160 ra->ra_avg_rssi, (rssi << 8)); 161 162 RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n", 163 ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), 164 rssi, last_avg_rssi, ra->ra_avg_rssi)); 165 } 166 167 /* 168 * Adapt the data rate to suit the conditions. When a transmitted 169 * packet is dropped after IEEE80211_RSSADAPT_RETRY_LIMIT retransmissions, 170 * raise the RSS threshold for transmitting packets of similar length at 171 * the same data rate. 172 */ 173 void 174 ieee80211_rssadapt_lower_rate(struct ieee80211com *ic, 175 const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, 176 const struct ieee80211_rssdesc *id) 177 { 178 const struct ieee80211_rateset *rs = &ni->ni_rates; 179 u_int16_t last_thr; 180 u_int i, thridx, top; 181 182 ra->ra_nfail++; 183 184 if (id->id_rateidx >= rs->rs_nrates) { 185 RSSADAPT_PRINTF(("ieee80211_rssadapt_lower_rate: " 186 "%s rate #%d > #%d out of bounds\n", 187 ether_sprintf((u_int8_t *)ni->ni_macaddr), id->id_rateidx, 188 rs->rs_nrates - 1)); 189 return; 190 } 191 192 for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 193 i < IEEE80211_RSSADAPT_BKTS; 194 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 195 thridx = i; 196 if (id->id_len <= top) 197 break; 198 } 199 200 last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx]; 201 ra->ra_rate_thresh[thridx][id->id_rateidx] = 202 interpolate(master_expavgctl.rc_thresh, last_thr, 203 (id->id_rssi << 8)); 204 205 RSSADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n", 206 ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), 207 id->id_rssi, id->id_len, 208 (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) / 2, 209 (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) * 5 % 10, 210 last_thr, ra->ra_rate_thresh[thridx][id->id_rateidx])); 211 } 212 213 void 214 ieee80211_rssadapt_raise_rate(struct ieee80211com *ic, 215 struct ieee80211_rssadapt *ra, const struct ieee80211_rssdesc *id) 216 { 217 u_int16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr; 218 const struct ieee80211_node *ni = id->id_node; 219 const struct ieee80211_rateset *rs = &ni->ni_rates; 220 int i, rate, top; 221 #ifdef IEEE80211_DEBUG 222 int j; 223 #endif 224 225 ra->ra_nok++; 226 227 if (!ratecheck(&ra->ra_last_raise, &ra->ra_raise_interval)) 228 return; 229 230 for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 231 i < IEEE80211_RSSADAPT_BKTS; 232 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 233 thrs = &ra->ra_rate_thresh[i]; 234 if (id->id_len <= top) 235 break; 236 } 237 238 if (id->id_rateidx + 1 < rs->rs_nrates && 239 (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) { 240 rate = (rs->rs_rates[id->id_rateidx + 1] & IEEE80211_RATE_VAL); 241 242 RSSADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ", 243 ic->ic_if.if_xname, IEEE80211_RSSADAPT_BKT0 << 244 (IEEE80211_RSSADAPT_BKTPOWER * i), 245 rate / 2, rate * 5 % 10, (*thrs)[id->id_rateidx + 1])); 246 oldthr = (*thrs)[id->id_rateidx + 1]; 247 if ((*thrs)[id->id_rateidx] == 0) 248 newthr = ra->ra_avg_rssi; 249 else 250 newthr = (*thrs)[id->id_rateidx]; 251 (*thrs)[id->id_rateidx + 1] = 252 interpolate(master_expavgctl.rc_decay, oldthr, newthr); 253 254 RSSADAPT_PRINTF(("-> %d\n", (*thrs)[id->id_rateidx + 1])); 255 } 256 257 #ifdef IEEE80211_DEBUG 258 if (RSSADAPT_DO_PRINT()) { 259 printf("%s: dst %s thresholds\n", ic->ic_if.if_xname, 260 ether_sprintf((u_int8_t *)ni->ni_macaddr)); 261 for (i = 0; i < IEEE80211_RSSADAPT_BKTS; i++) { 262 printf("%d-byte", IEEE80211_RSSADAPT_BKT0 << 263 (IEEE80211_RSSADAPT_BKTPOWER * i)); 264 for (j = 0; j < rs->rs_nrates; j++) { 265 rate = (rs->rs_rates[j] & IEEE80211_RATE_VAL); 266 printf(", T[%d.%d] = %d", rate / 2, 267 rate * 5 % 10, ra->ra_rate_thresh[i][j]); 268 } 269 printf("\n"); 270 } 271 } 272 #endif /* IEEE80211_DEBUG */ 273 } 274