From de5af7046072c36212844e2c527a53f94465a53b Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Mon, 15 Sep 2003 22:34:46 +0000 Subject: [PATCH] Maintain a history of data associated with received frames and use this to calculate smoothed signal quality data for each node. o add a 16-deep history buffer to each driver-private node storage that holds rssi and antenna info for received frames o override the default per-node "get rssi" method to return an average rssi value based on samples collected over the last second o enable beacon reception so even idle systems maintain a running history of signal quality This data may also be useful for improving the rate control algorithm. Based on work by Tom Marshall for MADWIFI. --- sys/dev/ath/if_ath.c | 72 ++++++++++++++++++++++++++++++++++++++--- sys/dev/ath/if_athvar.h | 10 ++++++ 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index aab78c03ea3c..61a86e0934dc 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -114,6 +114,8 @@ static struct ieee80211_node *ath_node_alloc(struct ieee80211com *); static void ath_node_free(struct ieee80211com *, struct ieee80211_node *); static void ath_node_copy(struct ieee80211com *, struct ieee80211_node *, const struct ieee80211_node *); +static u_int8_t ath_node_getrssi(struct ieee80211com *, + struct ieee80211_node *); static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *); static void ath_rx_proc(void *, int); static int ath_tx_start(struct ath_softc *, struct ieee80211_node *, @@ -290,6 +292,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) ic->ic_node_alloc = ath_node_alloc; ic->ic_node_free = ath_node_free; ic->ic_node_copy = ath_node_copy; + ic->ic_node_getrssi = ath_node_getrssi; sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = ath_newstate; /* complete initialization */ @@ -922,7 +925,8 @@ ath_mode_init(struct ath_softc *sc) if (ic->ic_opmode != IEEE80211_M_HOSTAP && (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; - if (ic->ic_state == IEEE80211_S_SCAN) + if (ic->ic_opmode == IEEE80211_M_STA || + ic->ic_state == IEEE80211_S_SCAN) rfilt |= HAL_RX_FILTER_BEACON; ath_hal_setrxfilter(ah, rfilt); @@ -1387,7 +1391,14 @@ ath_node_alloc(struct ieee80211com *ic) { struct ath_node *an = malloc(sizeof(struct ath_node), M_DEVBUF, M_NOWAIT | M_ZERO); - return an ? &an->an_node : NULL; + if (an) { + int i; + for (i = 0; i < ATH_RHIST_SIZE; i++) + an->an_rx_hist[i].arh_ticks = ATH_RHIST_NOTIME; + an->an_rx_hist_next = ATH_RHIST_SIZE-1; + return &an->an_node; + } else + return NULL; } static void @@ -1410,6 +1421,41 @@ ath_node_copy(struct ieee80211com *ic, *(struct ath_node *)dst = *(const struct ath_node *)src; } + +static u_int8_t +ath_node_getrssi(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct ath_node *an = ATH_NODE(ni); + int i, now, nsamples, rssi; + + /* + * Calculate the average over the last second of sampled data. + */ + now = ticks; + nsamples = 0; + rssi = 0; + i = an->an_rx_hist_next; + do { + struct ath_recv_hist *rh = &an->an_rx_hist[i]; + if (rh->arh_ticks == ATH_RHIST_NOTIME) + goto done; + if (now - rh->arh_ticks > hz) + goto done; + rssi += rh->arh_rssi; + nsamples++; + if (i == 0) + i = ATH_RHIST_SIZE-1; + else + i--; + } while (i != an->an_rx_hist_next); +done: + /* + * Return either the average or the last known + * value if there is no recent data. + */ + return (nsamples ? rssi / nsamples : an->an_rx_hist[i].arh_rssi); +} + static int ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) { @@ -1478,6 +1524,8 @@ ath_rx_proc(void *arg, int npending) struct mbuf *m; struct ieee80211_frame *wh, whbuf; struct ieee80211_node *ni; + struct ath_node *an; + struct ath_recv_hist *rh; int len; u_int phyerr; HAL_STATUS status; @@ -1588,12 +1636,24 @@ ath_rx_proc(void *arg, int npending) ni = ieee80211_ref_node(ic->ic_bss); } else ni = ieee80211_ref_node(ic->ic_bss); - ATH_NODE(ni)->an_rx_antenna = ds->ds_rxstat.rs_antenna; + + /* + * Record driver-specific state. + */ + an = ATH_NODE(ni); + if (++(an->an_rx_hist_next) == ATH_RHIST_SIZE) + an->an_rx_hist_next = 0; + rh = &an->an_rx_hist[an->an_rx_hist_next]; + rh->arh_ticks = ticks; + rh->arh_rssi = ds->ds_rxstat.rs_rssi; + rh->arh_antenna = ds->ds_rxstat.rs_antenna; + /* * Send frame up for processing. */ ieee80211_input(ifp, m, ni, ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp); + /* * The frame may have caused the node to be marked for * reclamation (e.g. in response to a DEAUTH message) @@ -1859,7 +1919,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf if (an->an_tx_antenna) antenna = an->an_tx_antenna; else - antenna = an->an_rx_antenna; + antenna = an->an_rx_hist[an->an_rx_hist_next].arh_antenna; /* * Formulate first tx descriptor with tx controls. @@ -2288,11 +2348,13 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) if (ic->ic_opmode != IEEE80211_M_HOSTAP && (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; + if (ic->ic_opmode == IEEE80211_M_STA || + ic->ic_state == IEEE80211_S_SCAN) + rfilt |= HAL_RX_FILTER_BEACON; if (nstate == IEEE80211_S_SCAN) { callout_reset(&sc->sc_scan_ch, (hz * ath_dwelltime) / 1000, ath_next_scan, sc); bssid = ifp->if_broadcastaddr; - rfilt |= HAL_RX_FILTER_BEACON; } else { callout_stop(&sc->sc_scan_ch); bssid = ni->ni_bssid; diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 73a7887d2aff..43578f4f599d 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -54,6 +54,14 @@ #define ATH_TXBUF 60 /* number of TX buffers */ #define ATH_TXDESC 8 /* number of descriptors per buffer */ +struct ath_recv_hist { + int arh_ticks; /* sample time by system clock */ + u_int8_t arh_rssi; /* rssi */ + u_int8_t arh_antenna; /* antenna */ +}; +#define ATH_RHIST_SIZE 16 /* number of samples */ +#define ATH_RHIST_NOTIME (~0) + /* driver-specific node */ struct ath_node { struct ieee80211_node an_node; /* base class */ @@ -63,6 +71,8 @@ struct ath_node { int an_tx_upper; /* tx upper rate req cnt */ u_int an_tx_antenna; /* antenna for last good frame */ u_int an_rx_antenna; /* antenna for last rcvd frame */ + struct ath_recv_hist an_rx_hist[ATH_RHIST_SIZE]; + u_int an_rx_hist_next;/* index of next ``free entry'' */ }; #define ATH_NODE(_n) ((struct ath_node *)(_n))