[otus] implement monitor mode.

* break out the operating mode and rx filter into new functions, rather
  than them being hard-coded
* if we're in sniffer mode or not associated, set the BSS MAC to all zero,
  rather than relying on a chip reset to do it for us
* add comments about .. how interestingly buggy the chip is.

Tested:

* AR9170 + AR9102, STA+monitor mode

Obtained from:	linux carl9170 (general chip workings, constant definitions)
This commit is contained in:
Adrian Chadd 2016-05-02 05:43:46 +00:00
parent afce6f3b0b
commit b35978d0da
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=298919

View File

@ -181,6 +181,8 @@ int otus_set_multi(struct otus_softc *);
static int otus_updateedca(struct ieee80211com *);
static void otus_updateedca_locked(struct otus_softc *);
static void otus_updateslot(struct otus_softc *);
static void otus_set_operating_mode(struct otus_softc *sc);
static void otus_set_rx_filter(struct otus_softc *sc);
int otus_init_mac(struct otus_softc *);
uint32_t otus_phy_get_def(struct otus_softc *, uint32_t);
int otus_set_board_values(struct otus_softc *,
@ -964,7 +966,7 @@ otus_alloc_cmd_list(struct otus_softc *sc, struct otus_tx_cmd cmd[],
for (i = 0; i < ndata; i++) {
struct otus_tx_cmd *dp = &cmd[i];
dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT | M_ZERO);
dp->odata = NULL;
if (dp->buf == NULL) {
device_printf(sc->sc_dev,
@ -1028,7 +1030,7 @@ otus_alloc_list(struct otus_softc *sc, struct otus_data data[],
struct otus_data *dp = &data[i];
dp->sc = sc;
dp->m = NULL;
dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT | M_ZERO);
if (dp->buf == NULL) {
device_printf(sc->sc_dev,
"could not allocate buffer\n");
@ -1142,6 +1144,7 @@ _otus_getbuf(struct otus_softc *sc)
STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
else
bf = NULL;
/* XXX bzero? */
return (bf);
}
@ -1224,7 +1227,6 @@ otus_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
struct otus_vap *uvp = OTUS_VAP(vap);
struct ieee80211com *ic = vap->iv_ic;
struct otus_softc *sc = ic->ic_softc;
struct ieee80211_node *ni;
enum ieee80211_state ostate;
ostate = vap->iv_state;
@ -1239,18 +1241,20 @@ otus_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
/* XXX TODO: more fleshing out! */
switch (nstate) {
case IEEE80211_S_INIT:
otus_set_operating_mode(sc);
otus_set_rx_filter(sc);
break;
case IEEE80211_S_RUN:
ni = ieee80211_ref_node(vap->iv_bss);
if (ic->ic_opmode == IEEE80211_M_STA) {
otus_updateslot(sc);
otus_set_bssid(sc, ni->ni_bssid);
otus_set_operating_mode(sc);
otus_set_rx_filter(sc);
/* Start calibration timer. */
taskqueue_enqueue_timeout(taskqueue_thread,
&sc->calib_to, hz);
}
ieee80211_free_node(ni);
break;
default:
break;
@ -2355,6 +2359,7 @@ otus_set_multi(struct otus_softc *sc)
otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_L, lo);
otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_H, hi);
r = otus_write_barrier(sc);
/* XXX operating mode? filter? */
OTUS_UNLOCK(sc);
return (r);
}
@ -2453,7 +2458,6 @@ otus_init_mac(struct otus_softc *sc)
otus_write(sc, AR_MAC_REG_ACK_EXTENSION, 0x40);
otus_write(sc, AR_MAC_REG_RETRY_MAX, 0);
otus_write(sc, AR_MAC_REG_SNIFFER, 0x2000000);
otus_write(sc, AR_MAC_REG_RX_THRESHOLD, 0xc1f80);
otus_write(sc, AR_MAC_REG_RX_PE_DELAY, 0x70);
otus_write(sc, AR_MAC_REG_EIFS_AND_SIFS, 0xa144000);
@ -2465,13 +2469,14 @@ otus_init_mac(struct otus_softc *sc)
otus_write(sc, AR_MAC_REG_BCN_HT1, 0x8000170);
otus_write(sc, AR_MAC_REG_BACKOFF_PROTECT, 0x105);
otus_write(sc, AR_MAC_REG_AMPDU_FACTOR, 0x10000a);
/* Filter any control frames, BAR is bit 24. */
// otus_write(sc, AR_MAC_REG_FRAMETYPE_FILTER, 0x0500ffff);
// otus_write(sc, AR_MAC_REG_RX_CONTROL, 0x1);
otus_set_rx_filter(sc);
otus_write(sc, AR_MAC_REG_BASIC_RATE, 0x150f);
otus_write(sc, AR_MAC_REG_MANDATORY_RATE, 0x150f);
otus_write(sc, AR_MAC_REG_RTS_CTS_RATE, 0x10b01bb);
otus_write(sc, AR_MAC_REG_ACK_TPC, 0x4003c1e);
/* Enable LED0 and LED1. */
otus_write(sc, AR_GPIO_REG_PORT_TYPE, 0x3);
otus_write(sc, AR_GPIO_REG_PORT_DATA, 0x3);
@ -3067,55 +3072,88 @@ otus_led_newstate_type3(struct otus_softc *sc)
#endif
}
static uint8_t zero_macaddr[IEEE80211_ADDR_LEN] = { 0,0,0,0,0,0 };
/*
* TODO:
*
* + If in monitor mode, set BSSID to all zeros, else the node BSSID.
* + Handle STA + monitor (eg tcpdump/promisc/radiotap) as well as
* pure monitor mode.
* Set up operating mode, MAC/BSS address and RX filter.
*/
static int
static void
otus_set_operating_mode(struct otus_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
uint32_t rx_ctrl;
uint32_t frm_filt;
uint32_t cam_mode;
uint32_t rx_sniffer;
struct ieee80211vap *vap;
uint32_t cam_mode = AR_MAC_CAM_DEFAULTS;
uint32_t rx_ctrl = AR_MAC_RX_CTRL_DEAGG | AR_MAC_RX_CTRL_SHORT_FILTER;
uint32_t sniffer = AR_MAC_SNIFFER_DEFAULTS;
uint32_t enc_mode = 0x78; /* XXX */
const uint8_t *macaddr;
uint8_t bssid[IEEE80211_ADDR_LEN];
struct ieee80211_node *ni;
OTUS_LOCK_ASSERT(sc);
/* XXX TODO: too many magic constants */
rx_ctrl = 0x1;
/* Filter any control frames, BAR is bit 24. */
frm_filt = 0x0500ffff;
cam_mode = 0x0f000002; /* XXX STA */
rx_sniffer = 0x20000000;
/*
* If we're in sniffer mode or we don't have a MAC
* address assigned, ensure it gets reset to all-zero.
*/
IEEE80211_ADDR_COPY(bssid, zero_macaddr);
vap = TAILQ_FIRST(&ic->ic_vaps);
macaddr = ic->ic_macaddr;
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
cam_mode = 0x0f000002; /* XXX STA */
rx_ctrl = 0x1;
frm_filt = 0x0500ffff;
rx_sniffer = 0x20000000;
if (vap) {
ni = ieee80211_ref_node(vap->iv_bss);
IEEE80211_ADDR_COPY(bssid, ni->ni_bssid);
ieee80211_free_node(ni);
}
cam_mode |= AR_MAC_CAM_STA;
rx_ctrl |= AR_MAC_RX_CTRL_PASS_TO_HOST;
break;
case IEEE80211_M_MONITOR:
cam_mode = 0x0f000002; /* XXX STA */
rx_ctrl = 0x1;
frm_filt = 0xffffffff;
rx_sniffer = 0x20000001;
break;
/*
* Note: monitor mode ends up causing the MAC to
* generate ACK frames for everything it sees.
* So don't do that; instead just put it in STA mode
* and disable RX filters.
*/
default:
cam_mode |= AR_MAC_CAM_STA;
rx_ctrl |= AR_MAC_RX_CTRL_PASS_TO_HOST;
break;
}
otus_write(sc, AR_MAC_REG_SNIFFER, rx_sniffer);
/*
* TODO: if/when we do hardware encryption, ensure it's
* disabled if the NIC is in monitor mode.
*/
otus_write(sc, AR_MAC_REG_SNIFFER, sniffer);
otus_write(sc, AR_MAC_REG_CAM_MODE, cam_mode);
otus_write(sc, AR_MAC_REG_FRAMETYPE_FILTER, frm_filt);
otus_write(sc, AR_MAC_REG_RX_CONTROL, cam_mode);
otus_write(sc, AR_MAC_REG_ENCRYPTION, enc_mode);
otus_write(sc, AR_MAC_REG_RX_CONTROL, rx_ctrl);
otus_set_macaddr(sc, macaddr);
otus_set_bssid(sc, bssid);
/* XXX barrier? */
}
(void) otus_write_barrier(sc);
return (0);
static void
otus_set_rx_filter(struct otus_softc *sc)
{
// struct ieee80211com *ic = &sc->sc_ic;
OTUS_LOCK_ASSERT(sc);
#if 0
if (ic->ic_allmulti > 0 || ic->ic_promisc > 0 ||
ic->ic_opmode == IEEE80211_M_MONITOR) {
otus_write(sc, AR_MAC_REG_FRAMETYPE_FILTER, 0xff00ffff);
} else {
#endif
/* Filter any control frames, BAR is bit 24. */
otus_write(sc, AR_MAC_REG_FRAMETYPE_FILTER, 0x0500ffff);
#if 0
}
#endif
}
int
@ -3139,7 +3177,8 @@ otus_init(struct otus_softc *sc)
return error;
}
(void) otus_set_macaddr(sc, ic->ic_macaddr);
otus_set_operating_mode(sc);
otus_set_rx_filter(sc);
(void) otus_set_operating_mode(sc);
sc->bb_reset = 1; /* Force cold reset. */