/* * Intercept management frames to collect beacon rssi data * and to do ibss merges. */ void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; /* * Call up first so subsequent work can use information * potentially stored in the node (e.g. for ibss merge). */ ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, nf); switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: /* update rssi statistics for use by the hal */ /* XXX unlocked check against vap->iv_bss? */ ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); if (sc->sc_syncbeacon && ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) { /* * Resync beacon timers using the tsf of the beacon * frame we just received. */ ath_beacon_config(sc, vap); } /* fall thru... */ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (vap->iv_opmode == IEEE80211_M_IBSS && vap->iv_state == IEEE80211_S_RUN) { uint32_t rstamp = sc->sc_lastrs->rs_tstamp; uint64_t tsf = ath_extend_tsf(sc, rstamp, ath_hal_gettsf64(sc->sc_ah)); /* * Handle ibss merge as needed; check the tsf on the * frame before attempting the merge. The 802.11 spec * says the station should change it's bssid to match * the oldest station with the same ssid, where oldest * is determined by the tsf. Note that hardware * reconfiguration happens through callback to * ath_newstate as the state machine will go from * RUN -> RUN when this happens. */ if (le64toh(ni->ni_tstamp.tsf) >= tsf) { DPRINTF(sc, ATH_DEBUG_STATE, "ibss merge, rstamp %u tsf %ju " "tstamp %ju\n", rstamp, (uintmax_t)tsf, (uintmax_t)ni->ni_tstamp.tsf); (void) ieee80211_ibss_merge(ni); } } break; } }
static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_rx_status *rx_stats) { struct ath_hw *ah = common->ah; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct ath_node *an; int last_rssi = ATH_RSSI_DUMMY_MARKER; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; rcu_read_lock(); /* * XXX: use ieee80211_find_sta! This requires quite a bit of work * under the current ath9k virtual wiphy implementation as we have * no way of tying a vif to wiphy. Typically vifs are attached to * at least one sdata of a wiphy on mac80211 but with ath9k virtual * wiphy you'd have to iterate over every wiphy and each sdata. */ sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); if (sta) { an = (struct ath_node *) sta->drv_priv; if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi); last_rssi = an->last_rssi; } rcu_read_unlock(); if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) rx_stats->rs_rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); if (rx_stats->rs_rssi < 0) rx_stats->rs_rssi = 0; /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) ah->stats.avgbrssi = rx_stats->rs_rssi; }
/* * Intercept management frames to collect beacon rssi data * and to do ibss merges. */ void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; struct ath_softc *sc = vap->iv_ic->ic_softc; uint64_t tsf_beacon_old, tsf_beacon; uint64_t nexttbtt; int64_t tsf_delta; int32_t tsf_delta_bmiss; int32_t tsf_remainder; uint64_t tsf_beacon_target; int tsf_intval; tsf_beacon_old = ((uint64_t) le32dec(ni->ni_tstamp.data + 4)) << 32; tsf_beacon_old |= le32dec(ni->ni_tstamp.data); #define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) tsf_intval = 1; if (ni->ni_intval > 0) { tsf_intval = TU_TO_TSF(ni->ni_intval); } #undef TU_TO_TSF /* * Call up first so subsequent work can use information * potentially stored in the node (e.g. for ibss merge). */ ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rxs, rssi, nf); switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: /* * Only do the following processing if it's for * the current BSS. * * In scan and IBSS mode we receive all beacons, * which means we need to filter out stuff * that isn't for us or we'll end up constantly * trying to sync / merge to BSSes that aren't * actually us. */ if (IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { /* update rssi statistics for use by the hal */ /* XXX unlocked check against vap->iv_bss? */ ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); tsf_beacon = ((uint64_t) le32dec(ni->ni_tstamp.data + 4)) << 32; tsf_beacon |= le32dec(ni->ni_tstamp.data); nexttbtt = ath_hal_getnexttbtt(sc->sc_ah); /* * Let's calculate the delta and remainder, so we can see * if the beacon timer from the AP is varying by more than * a few TU. (Which would be a huge, huge problem.) */ tsf_delta = (long long) tsf_beacon - (long long) tsf_beacon_old; tsf_delta_bmiss = tsf_delta / tsf_intval; /* * If our delta is greater than half the beacon interval, * let's round the bmiss value up to the next beacon * interval. Ie, we're running really, really early * on the next beacon. */ if (tsf_delta % tsf_intval > (tsf_intval / 2)) tsf_delta_bmiss ++; tsf_beacon_target = tsf_beacon_old + (((unsigned long long) tsf_delta_bmiss) * (long long) tsf_intval); /* * The remainder using '%' is between 0 .. intval-1. * If we're actually running too fast, then the remainder * will be some large number just under intval-1. * So we need to look at whether we're running * before or after the target beacon interval * and if we are, modify how we do the remainder * calculation. */ if (tsf_beacon < tsf_beacon_target) { tsf_remainder = -(tsf_intval - ((tsf_beacon - tsf_beacon_old) % tsf_intval)); } else { tsf_remainder = (tsf_beacon - tsf_beacon_old) % tsf_intval; } DPRINTF(sc, ATH_DEBUG_BEACON, "%s: old_tsf=%llu, new_tsf=%llu, target_tsf=%llu, delta=%lld, bmiss=%d, remainder=%d\n", __func__, (unsigned long long) tsf_beacon_old, (unsigned long long) tsf_beacon, (unsigned long long) tsf_beacon_target, (long long) tsf_delta, tsf_delta_bmiss, tsf_remainder); DPRINTF(sc, ATH_DEBUG_BEACON, "%s: tsf=%llu, nexttbtt=%llu, delta=%d\n", __func__, (unsigned long long) tsf_beacon, (unsigned long long) nexttbtt, (int32_t) tsf_beacon - (int32_t) nexttbtt + tsf_intval); /* We only do syncbeacon on STA VAPs; not on IBSS */ if (vap->iv_opmode == IEEE80211_M_STA && sc->sc_syncbeacon && ni == vap->iv_bss && (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) { DPRINTF(sc, ATH_DEBUG_BEACON, "%s: syncbeacon=1; syncing\n", __func__); /* * Resync beacon timers using the tsf of the beacon * frame we just received. */ ath_beacon_config(sc, vap); sc->sc_syncbeacon = 0; } } /* fall thru... */ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (vap->iv_opmode == IEEE80211_M_IBSS && vap->iv_state == IEEE80211_S_RUN && ieee80211_ibss_merge_check(ni)) { uint32_t rstamp = sc->sc_lastrs->rs_tstamp; uint64_t tsf = ath_extend_tsf(sc, rstamp, ath_hal_gettsf64(sc->sc_ah)); /* * Handle ibss merge as needed; check the tsf on the * frame before attempting the merge. The 802.11 spec * says the station should change it's bssid to match * the oldest station with the same ssid, where oldest * is determined by the tsf. Note that hardware * reconfiguration happens through callback to * ath_newstate as the state machine will go from * RUN -> RUN when this happens. */ if (le64toh(ni->ni_tstamp.tsf) >= tsf) { DPRINTF(sc, ATH_DEBUG_STATE, "ibss merge, rstamp %u tsf %ju " "tstamp %ju\n", rstamp, (uintmax_t)tsf, (uintmax_t)ni->ni_tstamp.tsf); (void) ieee80211_ibss_merge(ni); } } break; } }
void ath_rate_tx_complete_11n(struct ath_softc *sc, struct ath_node *an, struct ath_tx_status *ts, struct ath_rc_series rcs[], u_int8_t ac, int nframes, int nbad, int rts_retry_limit) #endif { int finalTSIdx = ts->ts_rateindex; int tx_status = 0, is_underrun = 0; struct atheros_node *oan = ATH_NODE_ATHEROS(an); struct ath_vap *avp = oan->avp->athdev_vap; #ifdef ATH_SUPPORT_TxBF if (rcs[0].flags & ATH_RC_SOUNDING_FLAG) { /* indicate sounding sent*/ ts->ts_txbfstatus |= TxBF_STATUS_Sounding_Complete; } if (oan->lastTxmcs0cnt > MCS0_80_PERCENT ){ /* clear TxBF HW status to avoid trigger sounding*/ ts->ts_txbfstatus &= ~(AR_TxBF_Valid_HW_Status); } #endif if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) || ts->ts_status & HAL_TXERR_FILT) { return; } #ifdef ATH_CHAINMASK_SELECT if (ts->ts_rssi > 0) { ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, ts->ts_rssi); } #endif /* * If underrun error is seen assume it as an excessive retry only if prefetch * trigger level have reached the max (0x3f for 5416) * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY times. This * affects how ratectrl updates PER for the failed rate. */ if ((HAL_IS_TX_UNDERRUN(ts)) && (ath_hal_gettxtriglevel(sc->sc_ah) >= sc->sc_rc->txTrigLevelMax)) { tx_status = 1; is_underrun = 1; } if (ts->ts_status & (HAL_TXERR_XRETRY |HAL_TXERR_FIFO)) { tx_status = 1; } RcUpdate_TxBF_STATS(sc, rcs, ts); #ifdef ATH_SUPPORT_VOWEXT #if ATH_SUPPORT_IQUE oan->rcFunc[ac].rcUpdate(sc, an, ts->ts_rssi, ac, finalTSIdx, tx_status, rcs, nframes , nbad, (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry, 0 , nHeadFail, nTailFail); #else rcUpdate_11n(sc, an, ts->ts_rssi , ac, finalTSIdx, tx_status, rcs, nframes , nbad, (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry, 0 , nHeadFail, nTailFail); #endif #else #if ATH_SUPPORT_IQUE oan->rcFunc[ac].rcUpdate(sc, an, ts->ts_rssi, ac, finalTSIdx, tx_status, rcs, nframes , nbad, (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry, 0 ); #else rcUpdate_11n(sc, an, ts->ts_rssi , ac, finalTSIdx, tx_status, rcs, nframes , nbad, (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry, 0 ); #endif #ifdef ATH_SUPPORT_TxBF if (oan->txbf_sounding_request){ ts->ts_txbfstatus |= TxBF_STATUS_Sounding_Request; oan->txbf_sounding_request = 0; } else { ts->ts_txbfstatus &= ~(TxBF_STATUS_Sounding_Request); } #endif #endif }