summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2016-05-02 05:43:46 +0000
committeradrian <adrian@FreeBSD.org>2016-05-02 05:43:46 +0000
commit0e2c2a615d6758c383ba050a494d83f9f1967482 (patch)
treeb0d61d82b2645f2f75cbe98b6221c9b23fb96502
parent64705f4816500d718745ff69750149606dedf839 (diff)
downloadFreeBSD-src-0e2c2a615d6758c383ba050a494d83f9f1967482.zip
FreeBSD-src-0e2c2a615d6758c383ba050a494d83f9f1967482.tar.gz
[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)
-rw-r--r--sys/dev/otus/if_otus.c123
1 files changed, 81 insertions, 42 deletions
diff --git a/sys/dev/otus/if_otus.c b/sys/dev/otus/if_otus.c
index 6539bbb..7b069a6 100644
--- a/sys/dev/otus/if_otus.c
+++ b/sys/dev/otus/if_otus.c
@@ -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. */
OpenPOWER on IntegriCloud