1 /* $OpenBSD: ieee80211_rssadapt.c,v 1.10 2011/03/02 08:48:59 fgsch 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 #ifdef INET 40 #include <netinet/in.h> 41 #include <netinet/if_ether.h> 42 #endif 43 44 #include <net80211/ieee80211_var.h> 45 #include <net80211/ieee80211_rssadapt.h> 46 47 #ifdef interpolate 48 #undef interpolate 49 #endif 50 #define interpolate(parm, old, new) \ 51 ((parm##_old * (old) + \ 52 (parm##_denom - parm##_old) * (new)) / parm##_denom) 53 54 #ifdef IEEE80211_DEBUG 55 static struct timeval lastrateadapt; /* time of last rate adaptation msg */ 56 static int currssadaptps = 0; /* rate-adaptation msgs this second */ 57 static int ieee80211_adaptrate = 4; /* rate-adaptation max msgs/sec */ 58 59 #define RSSADAPT_DO_PRINT() \ 60 ((ieee80211_rssadapt_debug > 0) && \ 61 ppsratecheck(&lastrateadapt, &currssadaptps, ieee80211_adaptrate)) 62 #define RSSADAPT_PRINTF(X) \ 63 if (RSSADAPT_DO_PRINT()) \ 64 printf X 65 66 int ieee80211_rssadapt_debug = 0; 67 68 #else 69 #define RSSADAPT_DO_PRINT() (0) 70 #define RSSADAPT_PRINTF(X) 71 #endif 72 73 static const struct ieee80211_rssadapt_expavgctl master_expavgctl = { 74 .rc_decay_denom = 16, 75 .rc_decay_old = 15, 76 .rc_thresh_denom = 8, 77 .rc_thresh_old = 4, 78 .rc_avgrssi_denom = 8, 79 .rc_avgrssi_old = 4 80 }; 81 82 int 83 ieee80211_rssadapt_choose(struct ieee80211_rssadapt *ra, 84 const struct ieee80211_rateset *rs, const struct ieee80211_frame *wh, 85 u_int len, int fixed_rate, const char *dvname, int do_not_adapt) 86 { 87 u_int16_t (*thrs)[IEEE80211_RATE_SIZE]; 88 int flags = 0, i, rateidx = 0, thridx, top; 89 90 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 91 flags |= IEEE80211_RATE_BASIC; 92 93 for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 94 i < IEEE80211_RSSADAPT_BKTS; 95 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 96 thridx = i; 97 if (len <= top) 98 break; 99 } 100 101 thrs = &ra->ra_rate_thresh[thridx]; 102 103 if (fixed_rate != -1) { 104 if ((rs->rs_rates[fixed_rate] & flags) == flags) { 105 rateidx = fixed_rate; 106 goto out; 107 } 108 flags |= IEEE80211_RATE_BASIC; 109 i = fixed_rate; 110 } else 111 i = rs->rs_nrates; 112 113 while (--i >= 0) { 114 rateidx = i; 115 if ((rs->rs_rates[i] & flags) != flags) 116 continue; 117 if (do_not_adapt) 118 break; 119 if ((*thrs)[i] < ra->ra_avg_rssi) 120 break; 121 } 122 123 out: 124 #ifdef IEEE80211_DEBUG 125 if (ieee80211_rssadapt_debug && dvname != NULL) { 126 printf("%s: dst %s threshold[%d, %d.%d] %d < %d\n", 127 dvname, ether_sprintf((u_int8_t *)wh->i_addr1), len, 128 (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) / 2, 129 (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) * 5 % 10, 130 (*thrs)[rateidx], ra->ra_avg_rssi); 131 } 132 #endif /* IEEE80211_DEBUG */ 133 return rateidx; 134 } 135 136 void 137 ieee80211_rssadapt_updatestats(struct ieee80211_rssadapt *ra) 138 { 139 long interval; 140 141 ra->ra_pktrate = 142 (ra->ra_pktrate + 10 * (ra->ra_nfail + ra->ra_nok)) / 2; 143 ra->ra_nfail = ra->ra_nok = 0; 144 145 /* a node is eligible for its rate to be raised every 1/10 to 10 146 * seconds, more eligible in proportion to recent packet rates. 147 */ 148 interval = MAX(100000, 10000000 / MAX(1, 10 * ra->ra_pktrate)); 149 ra->ra_raise_interval.tv_sec = interval / (1000 * 1000); 150 ra->ra_raise_interval.tv_usec = interval % (1000 * 1000); 151 } 152 153 void 154 ieee80211_rssadapt_input(struct ieee80211com *ic, 155 const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, int rssi) 156 { 157 #ifdef IEEE80211_DEBUG 158 int last_avg_rssi = ra->ra_avg_rssi; 159 #endif 160 161 ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi, 162 ra->ra_avg_rssi, (rssi << 8)); 163 164 RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n", 165 ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), 166 rssi, last_avg_rssi, ra->ra_avg_rssi)); 167 } 168 169 /* 170 * Adapt the data rate to suit the conditions. When a transmitted 171 * packet is dropped after IEEE80211_RSSADAPT_RETRY_LIMIT retransmissions, 172 * raise the RSS threshold for transmitting packets of similar length at 173 * the same data rate. 174 */ 175 void 176 ieee80211_rssadapt_lower_rate(struct ieee80211com *ic, 177 const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, 178 const struct ieee80211_rssdesc *id) 179 { 180 const struct ieee80211_rateset *rs = &ni->ni_rates; 181 u_int16_t last_thr; 182 u_int i, thridx, top; 183 184 ra->ra_nfail++; 185 186 if (id->id_rateidx >= rs->rs_nrates) { 187 RSSADAPT_PRINTF(("ieee80211_rssadapt_lower_rate: " 188 "%s rate #%d > #%d out of bounds\n", 189 ether_sprintf((u_int8_t *)ni->ni_macaddr), id->id_rateidx, 190 rs->rs_nrates - 1)); 191 return; 192 } 193 194 for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 195 i < IEEE80211_RSSADAPT_BKTS; 196 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 197 thridx = i; 198 if (id->id_len <= top) 199 break; 200 } 201 202 last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx]; 203 ra->ra_rate_thresh[thridx][id->id_rateidx] = 204 interpolate(master_expavgctl.rc_thresh, last_thr, 205 (id->id_rssi << 8)); 206 207 RSSADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n", 208 ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), 209 id->id_rssi, id->id_len, 210 (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) / 2, 211 (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) * 5 % 10, 212 last_thr, ra->ra_rate_thresh[thridx][id->id_rateidx])); 213 } 214 215 void 216 ieee80211_rssadapt_raise_rate(struct ieee80211com *ic, 217 struct ieee80211_rssadapt *ra, const struct ieee80211_rssdesc *id) 218 { 219 u_int16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr; 220 const struct ieee80211_node *ni = id->id_node; 221 const struct ieee80211_rateset *rs = &ni->ni_rates; 222 int i, rate, top; 223 #ifdef IEEE80211_DEBUG 224 int j; 225 #endif 226 227 ra->ra_nok++; 228 229 if (!ratecheck(&ra->ra_last_raise, &ra->ra_raise_interval)) 230 return; 231 232 for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 233 i < IEEE80211_RSSADAPT_BKTS; 234 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 235 thrs = &ra->ra_rate_thresh[i]; 236 if (id->id_len <= top) 237 break; 238 } 239 240 if (id->id_rateidx + 1 < rs->rs_nrates && 241 (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) { 242 rate = (rs->rs_rates[id->id_rateidx + 1] & IEEE80211_RATE_VAL); 243 244 RSSADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ", 245 ic->ic_if.if_xname, IEEE80211_RSSADAPT_BKT0 << 246 (IEEE80211_RSSADAPT_BKTPOWER * i), 247 rate / 2, rate * 5 % 10, (*thrs)[id->id_rateidx + 1])); 248 oldthr = (*thrs)[id->id_rateidx + 1]; 249 if ((*thrs)[id->id_rateidx] == 0) 250 newthr = ra->ra_avg_rssi; 251 else 252 newthr = (*thrs)[id->id_rateidx]; 253 (*thrs)[id->id_rateidx + 1] = 254 interpolate(master_expavgctl.rc_decay, oldthr, newthr); 255 256 RSSADAPT_PRINTF(("-> %d\n", (*thrs)[id->id_rateidx + 1])); 257 } 258 259 #ifdef IEEE80211_DEBUG 260 if (RSSADAPT_DO_PRINT()) { 261 printf("%s: dst %s thresholds\n", ic->ic_if.if_xname, 262 ether_sprintf((u_int8_t *)ni->ni_macaddr)); 263 for (i = 0; i < IEEE80211_RSSADAPT_BKTS; i++) { 264 printf("%d-byte", IEEE80211_RSSADAPT_BKT0 << 265 (IEEE80211_RSSADAPT_BKTPOWER * i)); 266 for (j = 0; j < rs->rs_nrates; j++) { 267 rate = (rs->rs_rates[j] & IEEE80211_RATE_VAL); 268 printf(", T[%d.%d] = %d", rate / 2, 269 rate * 5 % 10, ra->ra_rate_thresh[i][j]); 270 } 271 printf("\n"); 272 } 273 } 274 #endif /* IEEE80211_DEBUG */ 275 } 276