urtwn(4): improve RX filter.

- Filter out unneeded frames in STA mode.
- Implement ic_promisc() call.

Tested with RTL8188EU, STA and MONITOR modes.

Reviewed by:	kevlo
Approved by:	adrian (mentor)
Differential Revision:	https://reviews.freebsd.org/D3999
This commit is contained in:
Andriy Voskoboinyk 2015-11-08 23:21:54 +00:00
parent 24732d675d
commit 55dbdc2140
2 changed files with 103 additions and 30 deletions

View File

@ -269,6 +269,8 @@ static void urtwn_set_gain(struct urtwn_softc *, uint8_t);
static void urtwn_scan_start(struct ieee80211com *);
static void urtwn_scan_end(struct ieee80211com *);
static void urtwn_set_channel(struct ieee80211com *);
static void urtwn_set_promisc(struct urtwn_softc *);
static void urtwn_update_promisc(struct ieee80211com *);
static void urtwn_update_mcast(struct ieee80211com *);
static void urtwn_set_chan(struct urtwn_softc *,
struct ieee80211_channel *,
@ -457,6 +459,7 @@ urtwn_attach(device_t self)
ic->ic_parent = urtwn_parent;
ic->ic_vap_create = urtwn_vap_create;
ic->ic_vap_delete = urtwn_vap_delete;
ic->ic_update_promisc = urtwn_update_promisc;
ic->ic_update_mcast = urtwn_update_mcast;
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
@ -1574,22 +1577,6 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
break;
case IEEE80211_S_RUN:
if (vap->iv_opmode == IEEE80211_M_MONITOR) {
/* Enable Rx of data frames. */
urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
/* Enable Rx of ctrl frames. */
urtwn_write_2(sc, R92C_RXFLTMAP1, 0xffff);
/*
* Accept data/control/management frames
* from any BSSID.
*/
urtwn_write_4(sc, R92C_RCR,
(urtwn_read_4(sc, R92C_RCR) & ~(R92C_RCR_APM |
R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN)) |
R92C_RCR_ADF | R92C_RCR_ACF | R92C_RCR_AMF |
R92C_RCR_AAP);
/* Turn link LED on. */
urtwn_set_led(sc, URTWN_LED_LINK, 1);
break;
@ -1618,9 +1605,11 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
/* Allow Rx from our BSSID only. */
urtwn_write_4(sc, R92C_RCR,
urtwn_read_4(sc, R92C_RCR) |
R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
if (ic->ic_promisc == 0) {
urtwn_write_4(sc, R92C_RCR,
urtwn_read_4(sc, R92C_RCR) |
R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
}
/* Enable TSF synchronization. */
urtwn_tsf_sync_enable(sc);
@ -2755,21 +2744,50 @@ urtwn_pa_bias_init(struct urtwn_softc *sc)
static void
urtwn_rxfilter_init(struct urtwn_softc *sc)
{
/* Initialize Rx filter. */
/* TODO: use better filter for monitor mode. */
urtwn_write_4(sc, R92C_RCR,
R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB |
R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL |
R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS);
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
uint32_t rcr;
uint16_t filter;
URTWN_ASSERT_LOCKED(sc);
/* Accept all multicast frames. */
urtwn_write_4(sc, R92C_MAR + 0, 0xffffffff);
urtwn_write_4(sc, R92C_MAR + 4, 0xffffffff);
/* Accept all management frames. */
urtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff);
/* Filter for management frames. */
filter = 0x7f3f;
if (vap->iv_opmode == IEEE80211_M_STA) {
filter &= ~(
R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
}
urtwn_write_2(sc, R92C_RXFLTMAP0, filter);
/* Reject all control frames. */
urtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
/* Accept all data frames. */
urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
/* Reject all data frames. */
urtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
rcr = R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
if (vap->iv_opmode == IEEE80211_M_MONITOR) {
/* Accept all frames. */
rcr |= R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF |
R92C_RCR_AAP;
}
/* Set Rx filter. */
urtwn_write_4(sc, R92C_RCR, rcr);
if (ic->ic_promisc != 0) {
/* Update Rx filter. */
urtwn_set_promisc(sc);
}
}
static void
@ -3080,7 +3098,8 @@ urtwn_scan_end(struct ieee80211com *ic)
URTWN_LOCK(sc);
/* Restore limitations. */
urtwn_set_rx_bssid_all(sc, 0);
if (ic->ic_promisc == 0)
urtwn_set_rx_bssid_all(sc, 0);
/* Set gain under link. */
urtwn_set_gain(sc, 0x32);
URTWN_UNLOCK(sc);
@ -3101,6 +3120,52 @@ urtwn_set_channel(struct ieee80211com *ic)
URTWN_UNLOCK(sc);
}
static void
urtwn_set_promisc(struct urtwn_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
uint32_t rcr, mask1, mask2;
URTWN_ASSERT_LOCKED(sc);
if (vap->iv_opmode == IEEE80211_M_MONITOR)
return;
mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
mask2 = R92C_RCR_APM;
if (vap->iv_state == IEEE80211_S_RUN) {
switch (vap->iv_opmode) {
case IEEE80211_M_STA:
mask2 |= R92C_RCR_CBSSID_BCN | R92C_RCR_CBSSID_DATA;
break;
default:
device_printf(sc->sc_dev, "%s: undefined opmode %d\n",
__func__, vap->iv_opmode);
return;
}
}
rcr = urtwn_read_4(sc, R92C_RCR);
if (ic->ic_promisc == 0)
rcr = (rcr & ~mask1) | mask2;
else
rcr = (rcr & ~mask2) | mask1;
urtwn_write_4(sc, R92C_RCR, rcr);
}
static void
urtwn_update_promisc(struct ieee80211com *ic)
{
struct urtwn_softc *sc = ic->ic_softc;
URTWN_LOCK(sc);
if (sc->sc_flags & URTWN_RUNNING)
urtwn_set_promisc(sc);
URTWN_UNLOCK(sc);
}
static void
urtwn_update_mcast(struct ieee80211com *ic)
{
@ -3302,6 +3367,7 @@ urtwn_init(struct urtwn_softc *sc)
/* Set initial network type. */
urtwn_set_mode(sc, R92C_MSR_INFRA);
/* Initialize Rx filter. */
urtwn_rxfilter_init(sc);
/* Set response rate. */
@ -3375,6 +3441,9 @@ urtwn_init(struct urtwn_softc *sc)
urtwn_bb_init(sc);
urtwn_rf_init(sc);
/* Reinitialize Rx filter (D3845 is not committed yet). */
urtwn_rxfilter_init(sc);
if (sc->chip & URTWN_CHIP_88E) {
urtwn_write_2(sc, R92C_CR,
urtwn_read_2(sc, R92C_CR) | R92C_CR_MACTXEN |

View File

@ -535,6 +535,10 @@
#define R92C_CAMCMD_CLR 0x40000000
#define R92C_CAMCMD_POLLING 0x80000000
/* Bits for R92C_RXFLTMAP*. */
#define R92C_RXFLTMAP_SUBTYPE(subtype) \
(1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT))
/*
* Baseband registers.