void
ieee80211_rssadapt_raise_rate(struct ieee80211com *ic,
    struct ieee80211_rssadapt *ra, struct ieee80211_rssdesc *id)
{
	u_int16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr;
	struct ieee80211_node *ni = id->id_node;
	struct ieee80211_rateset *rs = &ni->ni_rates;
	int i, rate, top;
#ifdef IEEE80211_DEBUG
	int j;
#endif

	ra->ra_nok++;

	if (!ratecheck(&ra->ra_last_raise, &ra->ra_raise_interval))
		return;

	for (i = 0, top = IEEE80211_RSSADAPT_BKT0;
	     i < IEEE80211_RSSADAPT_BKTS;
	     i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) {
		thrs = &ra->ra_rate_thresh[i];
		if (id->id_len <= top)
			break;
	}

	if (id->id_rateidx + 1 < rs->rs_nrates &&
	    (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) {
		rate = (rs->rs_rates[id->id_rateidx + 1] & IEEE80211_RATE_VAL);

		RSSADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ",
		    ic->ic_ifp->if_xname,
		    IEEE80211_RSSADAPT_BKT0 << (IEEE80211_RSSADAPT_BKTPOWER* i),
		    rate / 2, rate * 5 % 10, (*thrs)[id->id_rateidx + 1]));
		oldthr = (*thrs)[id->id_rateidx + 1];
		if ((*thrs)[id->id_rateidx] == 0)
			newthr = ra->ra_avg_rssi;
		else
			newthr = (*thrs)[id->id_rateidx];
		(*thrs)[id->id_rateidx + 1] =
		    interpolate(master_expavgctl.rc_decay, oldthr, newthr);

		RSSADAPT_PRINTF(("-> %d\n", (*thrs)[id->id_rateidx + 1]));
	}

#ifdef IEEE80211_DEBUG
	if (RSSADAPT_DO_PRINT()) {
		printf("%s: dst %s thresholds\n", ic->ic_ifp->if_xname,
		    ether_sprintf(ni->ni_macaddr));
		for (i = 0; i < IEEE80211_RSSADAPT_BKTS; i++) {
			printf("%d-byte", IEEE80211_RSSADAPT_BKT0 << (IEEE80211_RSSADAPT_BKTPOWER * i));
			for (j = 0; j < rs->rs_nrates; j++) {
				rate = (rs->rs_rates[j] & IEEE80211_RATE_VAL);
				printf(", T[%d.%d] = %d", rate / 2,
				    rate * 5 % 10, ra->ra_rate_thresh[i][j]);
			}
			printf("\n");
		}
	}
#endif /* IEEE80211_DEBUG */
}
void
ieee80211_rssadapt_lower_rate(struct ieee80211_s *ic,
                              const struct ieee80211_node *ni,
                              struct ieee80211_rssadapt *ra,
                              const struct ieee80211_rssdesc *id)
{
  const struct ieee80211_rateset *rs = &ni->ni_rates;
  uint16_t last_thr;
  unsigned int i, thridx, top;

  ra->ra_nfail++;

  if (id->id_rateidx >= rs->rs_nrates)
    {
      RSSADAPT_PRINTF(("ieee80211_rssadapt_lower_rate: "
                       "%s rate #%d > #%d out of bounds\n",
                       ieee80211_addr2str((uint8_t *) ni->ni_macaddr),
                       id->id_rateidx, rs->rs_nrates - 1));
      return;
    }

  for (i = 0, top = IEEE80211_RSSADAPT_BKT0;
       i < IEEE80211_RSSADAPT_BKTS; i++, top <<= IEEE80211_RSSADAPT_BKTPOWER)
    {
      thridx = i;
      if (id->id_len <= top)
        break;
    }

  last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx];
  ra->ra_rate_thresh[thridx][id->id_rateidx] =
    interpolate(master_expavgctl.rc_thresh, last_thr, (id->id_rssi << 8));

  RSSADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n",
                   ic->ic_ifname,
                   ieee80211_addr2str((uint8_t *) ni->ni_macaddr), id->id_rssi,
                   id->id_len,
                   (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) / 2,
                   (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) * 5 % 10,
                   last_thr, ra->ra_rate_thresh[thridx][id->id_rateidx]));
}
void
ieee80211_rssadapt_input(struct ieee80211com *ic,
    const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, int rssi)
{
#ifdef IEEE80211_DEBUG
	int last_avg_rssi = ra->ra_avg_rssi;
#endif

	ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi,
	    ra->ra_avg_rssi, (rssi << 8));

	RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n",
	    ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr),
	    rssi, last_avg_rssi, ra->ra_avg_rssi));
}
void
ieee80211_rssadapt_input(struct ieee80211_s *ic,
                         const struct ieee80211_node *ni,
                         struct ieee80211_rssadapt *ra, int rssi)
{
#ifdef CONFIG_DEBUG_NET
  int last_avg_rssi = ra->ra_avg_rssi;
#endif

  ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi,
                                ra->ra_avg_rssi, (rssi << 8));

  RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n",
                   ic->ic_ifname,
                   ieee80211_addr2str((uint8_t *) ni->ni_macaddr), rssi,
                   last_avg_rssi, ra->ra_avg_rssi));
}