📄 if_ath_radar.c.svn-base
字号:
/* * This software is distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $Id: if_ath_radar.c 2464 2007-06-15 22:51:56Z mtaylor $ */#include "opt_ah.h"#include "if_ath_debug.h"#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/random.h>#include <linux/delay.h>#include <linux/cache.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/if_arp.h>#include <linux/rtnetlink.h>#include <linux/time.h>#include <asm/uaccess.h>#include <linux/param.h>#include "if_ethersubr.h" /* for ETHER_IS_MULTICAST */#include "if_media.h"#include "if_llc.h"#include <net80211/ieee80211_radiotap.h>#include <net80211/ieee80211_var.h>#include <net80211/ieee80211_monitor.h>#include <net80211/ieee80211_rate.h>#ifdef USE_HEADERLEN_RESV#include <net80211/if_llc.h>#endif#include "net80211/if_athproto.h"#include "if_athvar.h"#include "ah_desc.h"#include "ah_devid.h" /* XXX to identify chipset */#ifdef ATH_PCI /* PCI BUS */#include "if_ath_pci.h"#endif /* PCI BUS */#ifdef ATH_AHB /* AHB BUS */#include "if_ath_ahb.h"#endif /* AHB BUS */#undef MAX#define MAX(a, b) (((a) > (b)) ? (a) : (b))#undef MIN#define MIN(a, b) (((a) < (b)) ? (a) : (b))#include "ah.h"#include "if_ath_hal.h"#ifdef ATH_TX99_DIAG#include "ath_tx99.h"#endif#include "ah_os.h"#include "if_ath_radar.h"#define sizetab(t) (sizeof(t)/sizeof(t[0]))#define nofloat_pct(_value, _pct) \ ( (_value * (1000 + _pct)) / 1000 )struct radar_pattern_specification { /* The name of the rule/specification (i.e. what did we detect) */ const char *name; /* Interval MIN = 1000000 / FREQ - 2% * (a.k.a. Pulse/Burst Repetition Interval) */ u_int32_t min_rep_int; /* Interval MAX = 1000000 / FREQ + 2% * (a.k.a. Pulse/Burst Repetition Interval) */ u_int32_t max_rep_int; /* Do we adjust the min/max interval values dynamically * based upon running mean interval? */ HAL_BOOL dyn_ints; /* Fuzz factor dynamic matching, as unsigned integer percentage * of variation (i.e. 2 for +/- 2% timing) */ u_int32_t fuzz_pct; /* Match MIN (Minimum Pulse/Burst events required) */ u_int32_t min_pulse; /* Match MIN duration (Minimum Pulse/Burst events * required including missed) */ u_int32_t min_evts; /* Match MAX duration (Maximum Pulse/Burst events * required including missed) */ u_int32_t max_evts; /* Maximum consecutive missing pulses */ u_int32_t max_consecutive_missing; /* Maximum missing pulses */ u_int32_t max_missing; /* Match on absolute distance to PRI/PRF midpoint */ HAL_BOOL match_midpoint;};static struct radar_pattern_specification radar_patterns[] = {#ifdef DFS_DOMAIN_ETSI {"ETSI [ 200]", 4900, 5100, AH_FALSE, 20, 3, 4, 10, 4, 8, AH_TRUE}, {"ETSI [ 300]", 3267, 3399, AH_FALSE, 20, 3, 4, 10, 4, 6, AH_TRUE}, {"ETSI [ 500]", 1960, 2040, AH_FALSE, 20, 4, 4, 10, 4, 8, AH_TRUE}, {"ETSI [ 750]", 1307, 1359, AH_FALSE, 20, 5, 4, 15, 4, 13, AH_TRUE}, {"ETSI [ 800]", 1225, 1275, AH_FALSE, 20, 4, 4, 10, 4, 8, AH_TRUE}, {"ETSI [1000]", 980, 1020, AH_FALSE, 20, 4, 4, 10, 4, 8, AH_TRUE}, {"ETSI [1200]", 817, 849, AH_FALSE, 20, 5, 4, 15, 4, 13, AH_TRUE}, {"ETSI [1500]", 653, 679, AH_FALSE, 20, 5, 4, 15, 4, 6, AH_TRUE}, {"ETSI [1600]", 613, 637, AH_FALSE, 20, 5, 4, 15, 4, 7, AH_TRUE}, {"ETSI [2000]", 490, 510, AH_FALSE, 20, 7, 4, 20, 4, 10, AH_TRUE}, {"ETSI [2300]", 426, 442, AH_FALSE, 20, 9, 4, 25, 6, 20, AH_TRUE}, {"ETSI [3000]", 327, 339, AH_FALSE, 20, 7, 4, 20, 5, 20, AH_TRUE}, {"ETSI [3500]", 280, 290, AH_FALSE, 20, 9, 4, 25, 2, 20, AH_TRUE}, {"ETSI [4000]", 245, 255, AH_FALSE, 20, 7, 4, 20, 5, 20, AH_TRUE},#endif#ifdef DFS_DOMAIN_FCC {"FCC [1,1399-1714]", 1399, 1714, AH_TRUE, 10, 5, 10, 18, 4, 6, AH_FALSE}, {"FCC [2,147-235]", 147, 235, AH_TRUE, 10, 8, 10, 29, 6, 12, AH_FALSE}, {"FCC [3-4,196-273]", 196, 273, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}, {"FCC [3-4,275-352]", 275, 352, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}, {"FCC [3-4,354-431]", 354, 431, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}, {"FCC [3-4,433-510]", 433, 510, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}, {"FCC [3-4,235-313]", 235, 313, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}, {"FCC [3-4,314-392]", 314, 392, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}, {"FCC [3-4,393-471]", 393, 471, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}#endif};#ifdef AR_DEBUGstatic u_int32_t interval_to_frequency(u_int32_t pri);#endif /* AR_DEBUG *//* Returns true if radar detection is enabled. */int ath_radar_is_enabled(struct ath_softc *sc){ struct ath_hal *ah = sc->sc_ah; if (ar_device(sc->devid) >= 5211) return ((OS_REG_READ(ah, AR5K_AR5212_PHY_ERR_FIL) & AR5K_AR5212_PHY_ERR_FIL_RADAR) && (sc->sc_imask & HAL_INT_RXPHY) && (ath_hal_intrget(ah) & HAL_INT_RXPHY)); else return ((sc->sc_imask & HAL_INT_RXPHY) && (ath_hal_intrget(ah) & HAL_INT_RXPHY)); return 0;}/* Read the radar pulse detection parameters. */void ath_radar_get_params(struct ath_softc *sc, RADAR_PARAM *rp){ u_int32_t radar = ath_reg_read(sc, AR5K_PHY_RADAR); rp->rp_fir_filter_output_power_thr = (radar & AR5K_PHY_RADAR_FIRPWROUTTHR) >> AR5K_PHY_RADAR_FIRPWROUTTHR_S; rp->rp_radar_rssi_thr = (radar & AR5K_PHY_RADAR_PULSERSSITHR) >> AR5K_PHY_RADAR_PULSERSSITHR_S; rp->rp_pulse_height_thr = (radar & AR5K_PHY_RADAR_PULSEHEIGHTTHR) >> AR5K_PHY_RADAR_PULSEHEIGHTTHR_S; rp->rp_pulse_rssi_thr = (radar & AR5K_PHY_RADAR_RADARRSSITHR) >> AR5K_PHY_RADAR_RADARRSSITHR_S; rp->rp_inband_thr = (radar & AR5K_PHY_RADAR_INBANDTHR) >> AR5K_PHY_RADAR_INBANDTHR_S;}/* Update the radar pulse detection parameters. * If rp is NULL, defaults are used for all fields. * If any member of rp is set to RADAR_PARAM_USE_DEFAULT, the default * is used for that field. */void ath_radar_set_params(struct ath_softc *sc, RADAR_PARAM *rp){#define BUILD_PHY_RADAR_FIELD(_MASK,_SHIFT,_FIELD) \ ((NULL == rp || (rp->_FIELD == RADAR_PARAM_USE_DEFAULT)) ? \ ((AR5K_PHY_RADAR_ENABLED_AR5213 & (_MASK))) : \ ((rp->_FIELD << (_SHIFT)) & (_MASK))) ath_reg_write(sc, AR5K_PHY_RADAR, BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_FIRPWROUTTHR, AR5K_PHY_RADAR_FIRPWROUTTHR_S, rp_fir_filter_output_power_thr) | BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_RADARRSSITHR, AR5K_PHY_RADAR_RADARRSSITHR_S, rp_pulse_rssi_thr) | BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_PULSEHEIGHTTHR, AR5K_PHY_RADAR_PULSEHEIGHTTHR_S, rp_pulse_height_thr) | BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_PULSERSSITHR, AR5K_PHY_RADAR_PULSERSSITHR_S, rp_radar_rssi_thr) | BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_INBANDTHR, AR5K_PHY_RADAR_INBANDTHR_S, rp_inband_thr) );#undef BUILD_PHY_RADAR_FIELD}/* This is called on channel change to enable radar detection for 5211+ chips. * NOTE: AR5210 doesn't have radar pulse detection support. */int ath_radar_update(struct ath_softc *sc){ struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; int required = 0; /* Do not attempt to change radar state when bg scanning is * the cause */ if (ic->ic_flags & IEEE80211_F_SCAN) return 1; /* Update the DFS flags (as a sanity check) */ if (ath_radar_correct_dfs_flags(sc, &sc->sc_curchan)) DPRINTF(sc, ATH_DEBUG_DOTH, "%s: %s: channel required " "corrections to private flags.\n", SC_DEV_NAME(sc), __func__); required = ath_radar_is_dfs_required(sc, &sc->sc_curchan) && (ic->ic_flags & IEEE80211_F_DOTH); /* configure radar pulse detector register using default values, but do * not toggle the enable bit. XXX: allow tweaking?? */ ath_radar_set_params(sc, NULL); if (ar_device(sc->devid) >= 5211) { HAL_INT old_ier = ath_hal_intrget(ah); HAL_INT new_ier = old_ier; unsigned int old_radar = OS_REG_READ(ah, AR5K_PHY_RADAR); unsigned int old_filter = OS_REG_READ(ah, AR5K_AR5212_PHY_ERR_FIL); unsigned int old_rxfilt = ath_hal_getrxfilter(ah); unsigned int old_mask = sc->sc_imask; unsigned int new_radar = old_radar; unsigned int new_filter = old_filter; unsigned int new_mask = old_mask; unsigned int new_rxfilt = old_rxfilt; ath_hal_intrset(ah, old_ier & ~HAL_INT_GLOBAL); if (required) { new_radar |= AR5K_PHY_RADAR_ENABLE; new_filter |= AR5K_AR5212_PHY_ERR_FIL_RADAR; new_rxfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR); new_mask |= HAL_INT_RXPHY; new_ier |= HAL_INT_RXPHY; } else { new_radar &= ~AR5K_PHY_RADAR_ENABLE; new_filter &= ~AR5K_AR5212_PHY_ERR_FIL_RADAR; new_rxfilt &= ~HAL_RX_FILTER_PHYRADAR; new_mask &= ~HAL_INT_RXPHY; new_ier &= ~HAL_INT_RXPHY; } if (old_filter != new_filter) OS_REG_WRITE(ah, AR5K_AR5212_PHY_ERR_FIL, new_filter); if (old_radar != new_radar) OS_REG_WRITE(ah, AR5K_PHY_RADAR, new_radar); if (old_rxfilt != new_rxfilt) ath_hal_setrxfilter(ah, new_rxfilt); sc->sc_imask = new_mask; if (DFLAG_ISSET(sc, ATH_DEBUG_DOTH) && ((old_radar != new_radar) || (old_filter != new_filter) || (old_rxfilt != new_rxfilt) || (old_mask != new_mask) || (old_ier != new_ier))) { DPRINTF(sc, ATH_DEBUG_DOTH, "%s: %s: Radar detection %s.\n", SC_DEV_NAME(sc), __func__, required ? "enabled" : "disabled"); } ath_hal_intrset(ah, new_ier); } return (required == ath_radar_is_enabled(sc));}/* Update channel's DFS flags based upon whether DFS is required. Return * true if the value was repaired. */int ath_radar_correct_dfs_flags(struct ath_softc *sc, HAL_CHANNEL *hchan){ u_int32_t old_channelFlags = hchan->channelFlags; u_int32_t old_privFlags = hchan->privFlags; if (ath_radar_is_dfs_required(sc, hchan)) { hchan->channelFlags |= CHANNEL_PASSIVE; hchan->privFlags |= CHANNEL_DFS; } else { hchan->channelFlags &= ~CHANNEL_PASSIVE; hchan->privFlags &= ~CHANNEL_DFS; } return ((old_privFlags != hchan->privFlags) || (old_channelFlags != hchan->channelFlags));}/* Returns true if DFS is required for the regulatory domain, country and * combination in use. * XXX: Need to add regulatory rules in here. This is too conservative! */int ath_radar_is_dfs_required(struct ath_softc *sc, HAL_CHANNEL *hchan){ /* For FCC: 5250 to 5350MHz (channel 52 to 60) and for Europe added * 5470 to 5725 MHz (channel 100 to 140). * Being conservative, go with the entire band from 5250-5725 MHz. */ return ((hchan->channel >= 5250) && (hchan->channel <= 5725)) ? 1 : 0;}static struct ath_rp *pulse_head(struct ath_softc *sc){ return list_entry(sc->sc_rp_list.next, struct ath_rp, list);}static struct ath_rp *pulse_tail(struct ath_softc *sc){ return list_entry(sc->sc_rp_list.prev, struct ath_rp, list);}static struct ath_rp *pulse_prev(struct ath_rp *pulse){ return list_entry(pulse->list.prev, struct ath_rp, list);}#define CR_FALLTHROUGH 0#define CR_NULL 1#define CR_EXCESS_INTERVALS 2#define CR_INTERVALS 3#define CR_EXCESS_DURATION 4#define CR_DURATION 5#define CR_PULSES 6#define CR_MISSES 7#define CR_MIDPOINT_A 8#define CR_MIDPOINT_B 9#define CR_MIDPOINT_C 10#define CR_NOISE 11#define MR_MATCH 0#define MR_FAIL_MIN_INTERVALS 1#define MR_FAIL_REQD_MATCHES 2#define MR_FAIL_MAX_MISSES 3#define MR_FAIL_MIN_PERIOD 4#define MR_FAIL_MAX_PERIOD 5#ifdef AR_DEBUGstatic const char *get_match_result_desc(u_int32_t code){ switch (code) { case MR_MATCH: return "MATCH"; case MR_FAIL_MIN_INTERVALS: return "TOO-SHORT"; case MR_FAIL_REQD_MATCHES: return "TOO-FEW"; case MR_FAIL_MAX_MISSES: return "TOO-LOSSY"; case MR_FAIL_MIN_PERIOD: return "PRI<MIN"; case MR_FAIL_MAX_PERIOD: return "PRI>MAX"; default: return "unknown"; }}#endif /* AR_DEBUG */static int32_t match_radar( u_int32_t matched, u_int32_t missed, u_int32_t mean_period, u_int32_t noise, u_int32_t min_evts, u_int32_t max_evts, u_int32_t min_rep_int, u_int32_t max_rep_int, u_int32_t min_pulse, u_int32_t max_misses){ /* Not a match: insufficient overall burst length */ if ( (matched + missed) < min_evts) return MR_FAIL_MIN_INTERVALS; /* Not a match: insufficient match count */ if (matched < min_pulse) return MR_FAIL_REQD_MATCHES; /* Not a match: too many missies */ if (missed > max_misses) return MR_FAIL_MAX_MISSES; /* Not a match, PRI out of range */ if (mean_period < min_rep_int) return MR_FAIL_MIN_PERIOD; /* Not a match, PRI out of range */ if (mean_period > max_rep_int) return MR_FAIL_MAX_PERIOD; return MR_MATCH;}static int32_t compare_radar_matches( int32_t a_matched, int32_t a_missed, int32_t a_mean_period, int32_t a_noise, int32_t a_min_evts, int32_t a_max_evts, int32_t a_min_rep_int, int32_t a_max_rep_int, int32_t a_min_pulse,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -