1 1.21 christos /* $NetBSD: ieee80211_rssadapt.c,v 1.21 2016/09/27 20:20:06 christos Exp $ */ 2 1.1 dyoung /*- 3 1.1 dyoung * Copyright (c) 2003, 2004 David Young. All rights reserved. 4 1.1 dyoung * 5 1.1 dyoung * Redistribution and use in source and binary forms, with or 6 1.1 dyoung * without modification, are permitted provided that the following 7 1.1 dyoung * conditions are met: 8 1.1 dyoung * 1. Redistributions of source code must retain the above copyright 9 1.1 dyoung * notice, this list of conditions and the following disclaimer. 10 1.1 dyoung * 2. Redistributions in binary form must reproduce the above 11 1.1 dyoung * copyright notice, this list of conditions and the following 12 1.1 dyoung * disclaimer in the documentation and/or other materials provided 13 1.1 dyoung * with the distribution. 14 1.1 dyoung * 15 1.1 dyoung * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY 16 1.1 dyoung * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 1.1 dyoung * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 1.1 dyoung * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David 19 1.1 dyoung * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 1.1 dyoung * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 1.1 dyoung * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 dyoung * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 1.1 dyoung * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 dyoung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 dyoung * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 26 1.1 dyoung * OF SUCH DAMAGE. 27 1.1 dyoung */ 28 1.1 dyoung 29 1.11 dyoung #include <sys/cdefs.h> 30 1.11 dyoung #ifdef __NetBSD__ 31 1.21 christos __KERNEL_RCSID(0, "$NetBSD: ieee80211_rssadapt.c,v 1.21 2016/09/27 20:20:06 christos Exp $"); 32 1.11 dyoung #endif 33 1.11 dyoung 34 1.1 dyoung #include <sys/param.h> 35 1.1 dyoung #include <sys/types.h> 36 1.1 dyoung #include <sys/kernel.h> /* for hz */ 37 1.5 dyoung #include <sys/sysctl.h> 38 1.1 dyoung 39 1.1 dyoung #include <net/if.h> 40 1.1 dyoung #include <net/if_media.h> 41 1.1 dyoung #include <net/if_ether.h> 42 1.1 dyoung 43 1.11 dyoung #include <net80211/ieee80211_netbsd.h> 44 1.1 dyoung #include <net80211/ieee80211_var.h> 45 1.1 dyoung #include <net80211/ieee80211.h> 46 1.1 dyoung #include <net80211/ieee80211_rssadapt.h> 47 1.1 dyoung 48 1.3 dyoung #ifdef interpolate 49 1.3 dyoung #undef interpolate 50 1.3 dyoung #endif 51 1.3 dyoung #define interpolate(parm, old, new) ((parm##_old * (old) + \ 52 1.3 dyoung (parm##_denom - parm##_old) * (new)) / \ 53 1.3 dyoung parm##_denom) 54 1.3 dyoung 55 1.1 dyoung #ifdef IEEE80211_DEBUG 56 1.1 dyoung static struct timeval lastrateadapt; /* time of last rate adaptation msg */ 57 1.1 dyoung static int currssadaptps = 0; /* rate-adaptation msgs this second */ 58 1.1 dyoung static int ieee80211_adaptrate = 4; /* rate-adaptation max msgs/sec */ 59 1.1 dyoung 60 1.1 dyoung #define RSSADAPT_DO_PRINT() \ 61 1.5 dyoung ((ieee80211_rssadapt_debug > 0) && \ 62 1.1 dyoung ppsratecheck(&lastrateadapt, &currssadaptps, ieee80211_adaptrate)) 63 1.1 dyoung #define RSSADAPT_PRINTF(X) \ 64 1.1 dyoung if (RSSADAPT_DO_PRINT()) \ 65 1.1 dyoung printf X 66 1.1 dyoung 67 1.5 dyoung int ieee80211_rssadapt_debug = 0; 68 1.5 dyoung 69 1.1 dyoung #else 70 1.1 dyoung #define RSSADAPT_DO_PRINT() (0) 71 1.1 dyoung #define RSSADAPT_PRINTF(X) 72 1.1 dyoung #endif 73 1.1 dyoung 74 1.5 dyoung static struct ieee80211_rssadapt_expavgctl master_expavgctl = { 75 1.15 gmcgarry .rc_decay_denom = 16, 76 1.15 gmcgarry .rc_decay_old = 15, 77 1.15 gmcgarry .rc_thresh_denom = 8, 78 1.15 gmcgarry .rc_thresh_old = 4, 79 1.15 gmcgarry .rc_avgrssi_denom = 8, 80 1.15 gmcgarry .rc_avgrssi_old = 4 81 1.3 dyoung }; 82 1.3 dyoung 83 1.5 dyoung #ifdef __NetBSD__ 84 1.5 dyoung #ifdef IEEE80211_DEBUG 85 1.5 dyoung /* TBD factor with sysctl_ath_verify, sysctl_ieee80211_verify. */ 86 1.5 dyoung static int 87 1.5 dyoung sysctl_ieee80211_rssadapt_debug(SYSCTLFN_ARGS) 88 1.5 dyoung { 89 1.5 dyoung int error, t; 90 1.5 dyoung struct sysctlnode node; 91 1.5 dyoung 92 1.5 dyoung node = *rnode; 93 1.5 dyoung t = *(int*)rnode->sysctl_data; 94 1.5 dyoung node.sysctl_data = &t; 95 1.5 dyoung error = sysctl_lookup(SYSCTLFN_CALL(&node)); 96 1.5 dyoung if (error || newp == NULL) 97 1.5 dyoung return (error); 98 1.5 dyoung 99 1.5 dyoung if (t < 0 || t > 2) 100 1.5 dyoung return (EINVAL); 101 1.5 dyoung *(int*)rnode->sysctl_data = t; 102 1.5 dyoung 103 1.5 dyoung return (0); 104 1.5 dyoung } 105 1.5 dyoung #endif /* IEEE80211_DEBUG */ 106 1.5 dyoung 107 1.5 dyoung /* TBD factor with sysctl_ath_verify, sysctl_ieee80211_verify. */ 108 1.5 dyoung static int 109 1.5 dyoung sysctl_ieee80211_rssadapt_expavgctl(SYSCTLFN_ARGS) 110 1.5 dyoung { 111 1.5 dyoung struct ieee80211_rssadapt_expavgctl rc; 112 1.5 dyoung int error; 113 1.5 dyoung struct sysctlnode node; 114 1.5 dyoung 115 1.5 dyoung node = *rnode; 116 1.5 dyoung rc = *(struct ieee80211_rssadapt_expavgctl *)rnode->sysctl_data; 117 1.5 dyoung node.sysctl_data = &rc; 118 1.5 dyoung error = sysctl_lookup(SYSCTLFN_CALL(&node)); 119 1.5 dyoung if (error || newp == NULL) 120 1.5 dyoung return (error); 121 1.5 dyoung 122 1.14 christos if (/* rc.rc_decay_old < 0 || */ 123 1.5 dyoung rc.rc_decay_denom < rc.rc_decay_old) 124 1.5 dyoung return (EINVAL); 125 1.5 dyoung 126 1.14 christos if (/* rc.rc_thresh_old < 0 || */ 127 1.5 dyoung rc.rc_thresh_denom < rc.rc_thresh_old) 128 1.5 dyoung return (EINVAL); 129 1.5 dyoung 130 1.14 christos if (/* rc.rc_avgrssi_old < 0 || */ 131 1.5 dyoung rc.rc_avgrssi_denom < rc.rc_avgrssi_old) 132 1.5 dyoung return (EINVAL); 133 1.5 dyoung 134 1.5 dyoung *(struct ieee80211_rssadapt_expavgctl *)rnode->sysctl_data = rc; 135 1.5 dyoung 136 1.5 dyoung return (0); 137 1.5 dyoung } 138 1.5 dyoung 139 1.5 dyoung /* 140 1.5 dyoung * Setup sysctl(3) MIB, net.ieee80211.* 141 1.5 dyoung * 142 1.16 ad * TBD condition CTLFLAG_PERMANENT on being a module or not 143 1.5 dyoung */ 144 1.19 pooka void 145 1.19 pooka ieee80211_rssadapt_sysctl_setup(struct sysctllog **clog) 146 1.5 dyoung { 147 1.6 dyoung int rc; 148 1.10 atatat const struct sysctlnode *node; 149 1.5 dyoung 150 1.6 dyoung if ((rc = sysctl_createv(clog, 0, NULL, &node, 151 1.6 dyoung CTLFLAG_PERMANENT, CTLTYPE_NODE, "link", NULL, 152 1.18 pooka NULL, 0, NULL, 0, CTL_NET, PF_LINK, CTL_EOL)) != 0) 153 1.6 dyoung goto err; 154 1.6 dyoung 155 1.6 dyoung if ((rc = sysctl_createv(clog, 0, &node, &node, 156 1.5 dyoung CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211", NULL, 157 1.6 dyoung NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 158 1.5 dyoung goto err; 159 1.5 dyoung 160 1.6 dyoung if ((rc = sysctl_createv(clog, 0, &node, &node, 161 1.7 atatat CTLFLAG_PERMANENT, CTLTYPE_NODE, "rssadapt", 162 1.7 atatat SYSCTL_DESCR("Received Signal Strength adaptation controls"), 163 1.6 dyoung NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 164 1.5 dyoung goto err; 165 1.5 dyoung 166 1.5 dyoung #ifdef IEEE80211_DEBUG 167 1.5 dyoung /* control debugging printfs */ 168 1.6 dyoung if ((rc = sysctl_createv(clog, 0, &node, NULL, 169 1.7 atatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "debug", 170 1.7 atatat SYSCTL_DESCR("Enable RSS adaptation debugging output"), 171 1.5 dyoung sysctl_ieee80211_rssadapt_debug, 0, &ieee80211_rssadapt_debug, 0, 172 1.6 dyoung CTL_CREATE, CTL_EOL)) != 0) 173 1.5 dyoung goto err; 174 1.5 dyoung #endif /* IEEE80211_DEBUG */ 175 1.5 dyoung 176 1.5 dyoung /* control rate of decay for exponential averages */ 177 1.6 dyoung if ((rc = sysctl_createv(clog, 0, &node, NULL, 178 1.5 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT, 179 1.7 atatat "expavgctl", SYSCTL_DESCR("RSS exponential averaging control"), 180 1.7 atatat sysctl_ieee80211_rssadapt_expavgctl, 0, 181 1.6 dyoung &master_expavgctl, sizeof(master_expavgctl), CTL_CREATE, 182 1.6 dyoung CTL_EOL)) != 0) 183 1.5 dyoung goto err; 184 1.5 dyoung 185 1.5 dyoung return; 186 1.5 dyoung err: 187 1.5 dyoung printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 188 1.5 dyoung } 189 1.5 dyoung #endif /* __NetBSD__ */ 190 1.5 dyoung 191 1.3 dyoung int 192 1.3 dyoung ieee80211_rssadapt_choose(struct ieee80211_rssadapt *ra, 193 1.3 dyoung struct ieee80211_rateset *rs, struct ieee80211_frame *wh, u_int len, 194 1.3 dyoung int fixed_rate, const char *dvname, int do_not_adapt) 195 1.3 dyoung { 196 1.3 dyoung u_int16_t (*thrs)[IEEE80211_RATE_SIZE]; 197 1.3 dyoung int flags = 0, i, rateidx = 0, thridx, top; 198 1.3 dyoung 199 1.3 dyoung if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 200 1.3 dyoung flags |= IEEE80211_RATE_BASIC; 201 1.3 dyoung 202 1.3 dyoung for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 203 1.3 dyoung i < IEEE80211_RSSADAPT_BKTS; 204 1.3 dyoung i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 205 1.3 dyoung thridx = i; 206 1.3 dyoung if (len <= top) 207 1.3 dyoung break; 208 1.3 dyoung } 209 1.3 dyoung 210 1.3 dyoung thrs = &ra->ra_rate_thresh[thridx]; 211 1.3 dyoung 212 1.3 dyoung if (fixed_rate != -1) { 213 1.3 dyoung if ((rs->rs_rates[fixed_rate] & flags) == flags) { 214 1.3 dyoung rateidx = fixed_rate; 215 1.3 dyoung goto out; 216 1.3 dyoung } 217 1.3 dyoung flags |= IEEE80211_RATE_BASIC; 218 1.3 dyoung i = fixed_rate; 219 1.3 dyoung } else 220 1.3 dyoung i = rs->rs_nrates; 221 1.3 dyoung 222 1.3 dyoung while (--i >= 0) { 223 1.3 dyoung rateidx = i; 224 1.3 dyoung if ((rs->rs_rates[i] & flags) != flags) 225 1.3 dyoung continue; 226 1.3 dyoung if (do_not_adapt) 227 1.3 dyoung break; 228 1.3 dyoung if ((*thrs)[i] < ra->ra_avg_rssi) 229 1.3 dyoung break; 230 1.3 dyoung } 231 1.3 dyoung 232 1.3 dyoung out: 233 1.5 dyoung #ifdef IEEE80211_DEBUG 234 1.5 dyoung if (ieee80211_rssadapt_debug && dvname != NULL) { 235 1.3 dyoung printf("%s: dst %s threshold[%d, %d.%d] %d < %d\n", 236 1.3 dyoung dvname, ether_sprintf(wh->i_addr1), len, 237 1.3 dyoung (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) / 2, 238 1.3 dyoung (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) * 5 % 10, 239 1.3 dyoung (*thrs)[rateidx], ra->ra_avg_rssi); 240 1.3 dyoung } 241 1.5 dyoung #endif /* IEEE80211_DEBUG */ 242 1.3 dyoung return rateidx; 243 1.3 dyoung } 244 1.1 dyoung 245 1.1 dyoung void 246 1.1 dyoung ieee80211_rssadapt_updatestats(struct ieee80211_rssadapt *ra) 247 1.1 dyoung { 248 1.20 msaitoh long interval; 249 1.1 dyoung 250 1.1 dyoung ra->ra_pktrate = 251 1.1 dyoung (ra->ra_pktrate + 10 * (ra->ra_nfail + ra->ra_nok)) / 2; 252 1.1 dyoung ra->ra_nfail = ra->ra_nok = 0; 253 1.1 dyoung 254 1.1 dyoung /* a node is eligible for its rate to be raised every 1/10 to 10 255 1.1 dyoung * seconds, more eligible in proportion to recent packet rates. 256 1.1 dyoung */ 257 1.1 dyoung interval = MAX(100000, 10000000 / MAX(1, 10 * ra->ra_pktrate)); 258 1.1 dyoung ra->ra_raise_interval.tv_sec = interval / (1000 * 1000); 259 1.1 dyoung ra->ra_raise_interval.tv_usec = interval % (1000 * 1000); 260 1.1 dyoung } 261 1.1 dyoung 262 1.1 dyoung void 263 1.1 dyoung ieee80211_rssadapt_input(struct ieee80211com *ic, struct ieee80211_node *ni, 264 1.1 dyoung struct ieee80211_rssadapt *ra, int rssi) 265 1.1 dyoung { 266 1.2 dyoung #ifdef IEEE80211_DEBUG 267 1.1 dyoung int last_avg_rssi = ra->ra_avg_rssi; 268 1.2 dyoung #endif 269 1.1 dyoung 270 1.3 dyoung ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi, 271 1.3 dyoung ra->ra_avg_rssi, (rssi << 8)); 272 1.1 dyoung 273 1.1 dyoung RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n", 274 1.11 dyoung ic->ic_ifp->if_xname, ether_sprintf(ni->ni_macaddr), 275 1.1 dyoung rssi, last_avg_rssi, ra->ra_avg_rssi)); 276 1.1 dyoung } 277 1.1 dyoung 278 1.1 dyoung /* 279 1.1 dyoung * Adapt the data rate to suit the conditions. When a transmitted 280 1.1 dyoung * packet is dropped after IEEE80211_RSSADAPT_RETRY_LIMIT retransmissions, 281 1.1 dyoung * raise the RSS threshold for transmitting packets of similar length at 282 1.1 dyoung * the same data rate. 283 1.1 dyoung */ 284 1.1 dyoung void 285 1.1 dyoung ieee80211_rssadapt_lower_rate(struct ieee80211com *ic, 286 1.1 dyoung struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, 287 1.1 dyoung struct ieee80211_rssdesc *id) 288 1.1 dyoung { 289 1.1 dyoung struct ieee80211_rateset *rs = &ni->ni_rates; 290 1.1 dyoung u_int16_t last_thr; 291 1.1 dyoung u_int i, thridx, top; 292 1.1 dyoung 293 1.4 dyoung ra->ra_nfail++; 294 1.1 dyoung 295 1.1 dyoung if (id->id_rateidx >= rs->rs_nrates) { 296 1.1 dyoung RSSADAPT_PRINTF(("ieee80211_rssadapt_lower_rate: " 297 1.1 dyoung "%s rate #%d > #%d out of bounds\n", 298 1.1 dyoung ether_sprintf(ni->ni_macaddr), id->id_rateidx, 299 1.1 dyoung rs->rs_nrates - 1)); 300 1.1 dyoung return; 301 1.1 dyoung } 302 1.1 dyoung 303 1.1 dyoung for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 304 1.1 dyoung i < IEEE80211_RSSADAPT_BKTS; 305 1.1 dyoung i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 306 1.1 dyoung thridx = i; 307 1.1 dyoung if (id->id_len <= top) 308 1.1 dyoung break; 309 1.1 dyoung } 310 1.1 dyoung 311 1.1 dyoung last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx]; 312 1.1 dyoung ra->ra_rate_thresh[thridx][id->id_rateidx] = 313 1.3 dyoung interpolate(master_expavgctl.rc_thresh, last_thr, 314 1.3 dyoung (id->id_rssi << 8)); 315 1.1 dyoung 316 1.1 dyoung RSSADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n", 317 1.11 dyoung ic->ic_ifp->if_xname, ether_sprintf(ni->ni_macaddr), 318 1.1 dyoung id->id_rssi, id->id_len, 319 1.1 dyoung (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) / 2, 320 1.1 dyoung (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) * 5 % 10, 321 1.1 dyoung last_thr, ra->ra_rate_thresh[thridx][id->id_rateidx])); 322 1.1 dyoung } 323 1.1 dyoung 324 1.1 dyoung void 325 1.1 dyoung ieee80211_rssadapt_raise_rate(struct ieee80211com *ic, 326 1.1 dyoung struct ieee80211_rssadapt *ra, struct ieee80211_rssdesc *id) 327 1.1 dyoung { 328 1.1 dyoung u_int16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr; 329 1.1 dyoung struct ieee80211_node *ni = id->id_node; 330 1.1 dyoung struct ieee80211_rateset *rs = &ni->ni_rates; 331 1.2 dyoung int i, rate, top; 332 1.2 dyoung #ifdef IEEE80211_DEBUG 333 1.2 dyoung int j; 334 1.2 dyoung #endif 335 1.1 dyoung 336 1.4 dyoung ra->ra_nok++; 337 1.1 dyoung 338 1.1 dyoung if (!ratecheck(&ra->ra_last_raise, &ra->ra_raise_interval)) 339 1.1 dyoung return; 340 1.1 dyoung 341 1.1 dyoung for (i = 0, top = IEEE80211_RSSADAPT_BKT0; 342 1.1 dyoung i < IEEE80211_RSSADAPT_BKTS; 343 1.1 dyoung i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { 344 1.1 dyoung thrs = &ra->ra_rate_thresh[i]; 345 1.1 dyoung if (id->id_len <= top) 346 1.1 dyoung break; 347 1.1 dyoung } 348 1.1 dyoung 349 1.1 dyoung if (id->id_rateidx + 1 < rs->rs_nrates && 350 1.1 dyoung (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) { 351 1.1 dyoung rate = (rs->rs_rates[id->id_rateidx + 1] & IEEE80211_RATE_VAL); 352 1.1 dyoung 353 1.21 christos __USE(rate); 354 1.1 dyoung RSSADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ", 355 1.11 dyoung ic->ic_ifp->if_xname, 356 1.1 dyoung IEEE80211_RSSADAPT_BKT0 << (IEEE80211_RSSADAPT_BKTPOWER* i), 357 1.1 dyoung rate / 2, rate * 5 % 10, (*thrs)[id->id_rateidx + 1])); 358 1.1 dyoung oldthr = (*thrs)[id->id_rateidx + 1]; 359 1.1 dyoung if ((*thrs)[id->id_rateidx] == 0) 360 1.1 dyoung newthr = ra->ra_avg_rssi; 361 1.1 dyoung else 362 1.1 dyoung newthr = (*thrs)[id->id_rateidx]; 363 1.1 dyoung (*thrs)[id->id_rateidx + 1] = 364 1.3 dyoung interpolate(master_expavgctl.rc_decay, oldthr, newthr); 365 1.1 dyoung 366 1.1 dyoung RSSADAPT_PRINTF(("-> %d\n", (*thrs)[id->id_rateidx + 1])); 367 1.1 dyoung } 368 1.1 dyoung 369 1.1 dyoung #ifdef IEEE80211_DEBUG 370 1.1 dyoung if (RSSADAPT_DO_PRINT()) { 371 1.11 dyoung printf("%s: dst %s thresholds\n", ic->ic_ifp->if_xname, 372 1.1 dyoung ether_sprintf(ni->ni_macaddr)); 373 1.1 dyoung for (i = 0; i < IEEE80211_RSSADAPT_BKTS; i++) { 374 1.1 dyoung printf("%d-byte", IEEE80211_RSSADAPT_BKT0 << (IEEE80211_RSSADAPT_BKTPOWER * i)); 375 1.1 dyoung for (j = 0; j < rs->rs_nrates; j++) { 376 1.1 dyoung rate = (rs->rs_rates[j] & IEEE80211_RATE_VAL); 377 1.1 dyoung printf(", T[%d.%d] = %d", rate / 2, 378 1.1 dyoung rate * 5 % 10, ra->ra_rate_thresh[i][j]); 379 1.1 dyoung } 380 1.1 dyoung printf("\n"); 381 1.1 dyoung } 382 1.1 dyoung } 383 1.1 dyoung #endif /* IEEE80211_DEBUG */ 384 1.1 dyoung } 385