svn commit: r309825 - head/sys/dev/usb/wlan

Andriy Voskoboinyk avos at FreeBSD.org
Sat Dec 10 18:47:15 UTC 2016


Author: avos
Date: Sat Dec 10 18:47:13 2016
New Revision: 309825
URL: https://svnweb.freebsd.org/changeset/base/309825

Log:
  rsu: add promiscuous mode support.
  
  - Add partial promiscuous mode support (no management frames;
  they cannot be received by the firmware and net80211 at the same time).
  - Add monitor mode support (all frames).
  
  Tested with Asus, USB-N10.

Modified:
  head/sys/dev/usb/wlan/if_rsu.c
  head/sys/dev/usb/wlan/if_rsureg.h

Modified: head/sys/dev/usb/wlan/if_rsu.c
==============================================================================
--- head/sys/dev/usb/wlan/if_rsu.c	Sat Dec 10 18:29:39 2016	(r309824)
+++ head/sys/dev/usb/wlan/if_rsu.c	Sat Dec 10 18:47:13 2016	(r309825)
@@ -23,7 +23,7 @@ __FBSDID("$FreeBSD$");
  *
  * TODO:
  *   o tx a-mpdu
- *   o monitor / hostap / ibss / mesh
+ *   o hostap / ibss / mesh
  *   o power-save operation
  */
 
@@ -175,6 +175,7 @@ static void	rsu_getradiocaps(struct ieee
 static void	rsu_set_channel(struct ieee80211com *);
 static void	rsu_scan_curchan(struct ieee80211_scan_state *, unsigned long);
 static void	rsu_scan_mindwell(struct ieee80211_scan_state *);
+static void	rsu_update_promisc(struct ieee80211com *);
 static uint8_t	rsu_get_multi_pos(const uint8_t[]);
 static void	rsu_set_multi(struct rsu_softc *);
 static void	rsu_update_mcast(struct ieee80211com *);
@@ -202,6 +203,9 @@ static int	rsu_read_rom(struct rsu_softc
 static int	rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int);
 static void	rsu_calib_task(void *, int);
 static void	rsu_tx_task(void *, int);
+static void	rsu_set_led(struct rsu_softc *, int);
+static int	rsu_monitor_newstate(struct ieee80211vap *,
+		    enum ieee80211_state, int);
 static int	rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static int	rsu_key_alloc(struct ieee80211vap *, struct ieee80211_key *,
 		    ieee80211_keyix *, ieee80211_keyix *);
@@ -244,6 +248,9 @@ static struct mbuf *
 static void	rsu_txeof(struct usb_xfer *, struct rsu_data *);
 static int	rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, 
 		    const struct ieee80211_bpf_params *);
+static void	rsu_rxfilter_init(struct rsu_softc *);
+static void	rsu_rxfilter_set(struct rsu_softc *, uint32_t, uint32_t);
+static void	rsu_rxfilter_refresh(struct rsu_softc *);
 static void	rsu_init(struct rsu_softc *);
 static int	rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, 
 		    struct mbuf *, struct rsu_data *);
@@ -536,6 +543,7 @@ rsu_attach(device_t self)
 	/* Set device capabilities. */
 	ic->ic_caps =
 	    IEEE80211_C_STA |		/* station mode */
+	    IEEE80211_C_MONITOR |	/* monitor mode supported */
 #if 0
 	    IEEE80211_C_BGSCAN |	/* Background scan. */
 #endif
@@ -582,6 +590,7 @@ rsu_attach(device_t self)
 	ic->ic_scan_mindwell = rsu_scan_mindwell;
 	ic->ic_vap_create = rsu_vap_create;
 	ic->ic_vap_delete = rsu_vap_delete;
+	ic->ic_update_promisc = rsu_update_promisc;
 	ic->ic_update_mcast = rsu_update_mcast;
 	ic->ic_parent = rsu_parent;
 	ic->ic_transmit = rsu_transmit;
@@ -688,7 +697,10 @@ rsu_vap_create(struct ieee80211com *ic, 
 
 	/* override state transition machine */
 	uvp->newstate = vap->iv_newstate;
-	vap->iv_newstate = rsu_newstate;
+	if (opmode == IEEE80211_M_MONITOR)
+		vap->iv_newstate = rsu_monitor_newstate;
+	else
+		vap->iv_newstate = rsu_newstate;
 	vap->iv_key_alloc = rsu_key_alloc;
 	vap->iv_key_set = rsu_key_set;
 	vap->iv_key_delete = rsu_key_delete;
@@ -759,9 +771,30 @@ rsu_getradiocaps(struct ieee80211com *ic
 }
 
 static void
-rsu_set_channel(struct ieee80211com *ic __unused)
+rsu_set_channel(struct ieee80211com *ic)
 {
-	/* We are unable to switch channels, yet. */
+	struct rsu_softc *sc = ic->ic_softc;
+
+	/*
+	 * Only need to set the channel in Monitor mode. AP scanning and auth
+	 * are already taken care of by their respective firmware commands.
+	 */	
+	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+		struct r92s_set_channel cmd;
+		int error;
+
+		cmd.channel = IEEE80211_CHAN2IEEE(ic->ic_curchan);
+
+		RSU_LOCK(sc);
+		error = rsu_fw_cmd(sc, R92S_CMD_SET_CHANNEL, &cmd,
+		    sizeof(cmd));
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: error %d setting channel\n", __func__,
+			    error);
+		}
+		RSU_UNLOCK(sc);
+	}
 }
 
 static void
@@ -782,6 +815,17 @@ rsu_scan_mindwell(struct ieee80211_scan_
 	/* NB: don't try to abort scan; wait for firmware to finish */
 }
 
+static void
+rsu_update_promisc(struct ieee80211com *ic)
+{
+	struct rsu_softc *sc = ic->ic_softc;
+
+	RSU_LOCK(sc);
+	if (sc->sc_running)
+		rsu_rxfilter_refresh(sc);
+	RSU_UNLOCK(sc);
+}
+
 /*
  * The same as rtwn_get_multi_pos() / rtwn_set_multi().
  */
@@ -1343,6 +1387,47 @@ rsu_set_fw_power_state(struct rsu_softc 
 	return (error);
 }
 
+static void
+rsu_set_led(struct rsu_softc *sc, int on)
+{
+	rsu_write_1(sc, R92S_LEDCFG,
+	    (rsu_read_1(sc, R92S_LEDCFG) & 0xf0) | (!on << 3));
+}
+
+static int
+rsu_monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate,
+    int arg)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rsu_softc *sc = ic->ic_softc;
+	struct rsu_vap *uvp = RSU_VAP(vap);
+
+	if (vap->iv_state != nstate) {
+		IEEE80211_UNLOCK(ic);
+		RSU_LOCK(sc);
+
+		switch (nstate) {
+		case IEEE80211_S_INIT:
+			sc->sc_vap_is_running = 0;
+			rsu_set_led(sc, 0);
+			break;
+		case IEEE80211_S_RUN:
+			sc->sc_vap_is_running = 1;
+			rsu_set_led(sc, 1);
+			break;
+		default:
+			/* NOTREACHED */
+			break;
+		}
+		rsu_rxfilter_refresh(sc);
+
+		RSU_UNLOCK(sc);
+		IEEE80211_LOCK(ic);
+	}
+
+	return (uvp->newstate(vap, nstate, arg));
+}
+
 static int
 rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
@@ -1376,6 +1461,12 @@ rsu_newstate(struct ieee80211vap *vap, e
 		RSU_LOCK(sc);
 		/* Disassociate from our current BSS. */
 		rsu_disconnect(sc);
+		usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
+
+		/* Refresh Rx filter (may be modified by firmware). */
+		sc->sc_vap_is_running = 0;
+		rsu_rxfilter_refresh(sc);
+
 		/* Reinstall static keys. */
 		if (sc->sc_running)
 			rsu_reinit_static_keys(sc);
@@ -2030,6 +2121,11 @@ rsu_event_join_bss(struct rsu_softc *sc,
 	    __func__, ether_sprintf(rsp->bss.macaddr), tmp);
 	/* XXX is this required? What's the top two bits for again? */
 	ni->ni_associd = tmp | 0xc000;
+
+	/* Refresh Rx filter (was changed by firmware). */
+	sc->sc_vap_is_running = 1;
+	rsu_rxfilter_refresh(sc);
+
 	RSU_UNLOCK(sc);
 	ieee80211_new_state(vap, IEEE80211_S_RUN,
 	    IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
@@ -3329,6 +3425,65 @@ rsu_raw_xmit(struct ieee80211_node *ni, 
 }
 
 static void
+rsu_rxfilter_init(struct rsu_softc *sc)
+{
+	uint32_t reg;
+
+	RSU_ASSERT_LOCKED(sc);
+
+	/* Setup multicast filter. */
+	rsu_set_multi(sc);
+
+	/* Adjust Rx filter. */
+	reg = rsu_read_4(sc, R92S_RCR);
+	reg &= ~R92S_RCR_AICV;
+	reg |= R92S_RCR_APP_PHYSTS;
+	rsu_write_4(sc, R92S_RCR, reg);
+
+	/* Update dynamic Rx filter parts. */
+	rsu_rxfilter_refresh(sc);
+}
+
+static void
+rsu_rxfilter_set(struct rsu_softc *sc, uint32_t clear, uint32_t set)
+{
+	/* NB: firmware can touch this register too. */
+	rsu_write_4(sc, R92S_RCR,
+	   (rsu_read_4(sc, R92S_RCR) & ~clear) | set);
+}
+
+static void
+rsu_rxfilter_refresh(struct rsu_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t mask_all, mask_min;
+
+	RSU_ASSERT_LOCKED(sc);
+
+	/* NB: RCR_AMF / RXFLTMAP_MGT are used by firmware. */
+	mask_all = R92S_RCR_ACF | R92S_RCR_AAP;
+	mask_min = R92S_RCR_APM;
+	if (sc->sc_vap_is_running)
+		mask_min |= R92S_RCR_CBSSID;
+	else
+		mask_all |= R92S_RCR_ADF;
+
+	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+		uint16_t rxfltmap;
+		if (sc->sc_vap_is_running)
+			rxfltmap = 0;
+		else
+			rxfltmap = R92S_RXFLTMAP_MGT_DEF;
+		rsu_write_2(sc, R92S_RXFLTMAP_MGT, rxfltmap);
+	}
+
+	if (ic->ic_promisc == 0 && ic->ic_opmode != IEEE80211_M_MONITOR)
+		rsu_rxfilter_set(sc, mask_all, mask_min);
+	else
+		rsu_rxfilter_set(sc, mask_min, mask_all);
+}
+
+static void
 rsu_init(struct rsu_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
@@ -3394,12 +3549,8 @@ rsu_init(struct rsu_softc *sc)
 		goto fail;
 	}
 
-	/* Append PHY status. */
-	rsu_write_4(sc, R92S_RCR,
-	    rsu_read_4(sc, R92S_RCR) | 0x02000000);
-
-	/* Setup multicast filter (must be done after firmware loading). */
-	rsu_set_multi(sc);
+	/* Initialize Rx filter. */
+	rsu_rxfilter_init(sc);
 
 	/* Set PS mode fully active */
 	error = rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE);
@@ -3433,6 +3584,7 @@ rsu_stop(struct rsu_softc *sc)
 	RSU_ASSERT_LOCKED(sc);
 
 	sc->sc_running = 0;
+	sc->sc_vap_is_running = 0;
 	sc->sc_calibrating = 0;
 	taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL);
 	taskqueue_cancel(taskqueue_thread, &sc->tx_task, NULL);

Modified: head/sys/dev/usb/wlan/if_rsureg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_rsureg.h	Sat Dec 10 18:29:39 2016	(r309824)
+++ head/sys/dev/usb/wlan/if_rsureg.h	Sat Dec 10 18:47:13 2016	(r309825)
@@ -54,6 +54,12 @@
 #define R92S_TIMECTRL		0x0080
 #define R92S_TSFTR		(R92S_TIMECTRL + 0x000)
 
+#define R92S_FIFOCTRL		0x00a0
+#define R92S_RXFLTMAP_MGT	(R92S_FIFOCTRL + 0x076)
+#define R92S_RXFLTMAP_CTL	(R92S_FIFOCTRL + 0x078)
+#define R92S_RXFLTMAP_DATA	(R92S_FIFOCTRL + 0x07a)
+#define R92S_RXFLTMAP_MESH	(R92S_FIFOCTRL + 0x07c)
+
 #define R92S_SECURITY		0x0240
 #define R92S_CAMCMD		(R92S_SECURITY + 0x000)
 #define R92S_CAMWRITE		(R92S_SECURITY + 0x004)
@@ -63,6 +69,7 @@
 #define R92S_GPIO_CTRL		(R92S_GP + 0x00c)
 #define R92S_GPIO_IO_SEL	(R92S_GP + 0x00e)
 #define R92S_MAC_PINMUX_CTRL	(R92S_GP + 0x011)
+#define R92S_LEDCFG		(R92S_GP + 0x012)
 
 #define R92S_IOCMD_CTRL		0x0370
 #define R92S_IOCMD_DATA		0x0374
@@ -141,6 +148,29 @@
 #define R92S_TCR_IMEM_RDY	0x20
 #define R92S_TCR_FWRDY		0x80
 
+/* Bits for R92S_RCR. */
+#define R92S_RCR_AAP		0x00000001
+#define R92S_RCR_APM		0x00000002
+#define R92S_RCR_AM		0x00000004
+#define R92S_RCR_AB		0x00000008
+#define R92S_RCR_ACRC32		0x00000020
+#define R92S_RCR_AICV		0x00001000
+#define R92S_RCR_APP_ICV	0x00010000
+#define R92S_RCR_APP_MIC	0x00020000
+#define R92S_RCR_ADF		0x00040000
+#define R92S_RCR_ACF		0x00080000
+#define R92S_RCR_AMF		0x00100000
+#define R92S_RCR_ADD3		0x00200000
+#define R92S_RCR_APWRMGT	0x00400000
+#define R92S_RCR_CBSSID		0x00800000
+#define R92S_RCR_APP_PHYSTS	0x02000000
+#define R92S_RCR_ENMBID		0x08000000
+
+/* Bits for R92S_RXFLTMAP*. */
+#define R92S_RXFLTMAP_MGT_DEF	0x3f3f
+#define R92S_RXFLTMAP_FW(subtype)	\
+	(1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT))
+
 /* Bits for R92S_GPIO_IO_SEL. */
 #define R92S_GPIO_WPS	0x10
 
@@ -546,6 +576,11 @@ struct r92s_set_pwr_mode {
 	uint8_t		bcn_pass_time;
 } __packed;
 
+/* Structure for R92S_CMD_SET_CHANNEL. */
+struct r92s_set_channel {
+	uint32_t	channel;
+} __packed;
+
 /* Structure for event R92S_EVENT_JOIN_BSS. */
 struct r92s_event_join_bss {
 	uint32_t	next;
@@ -817,6 +852,7 @@ struct rsu_softc {
 	int				sc_currssi;
 
 	u_int				sc_running:1,
+					sc_vap_is_running:1,
 					sc_calibrating:1,
 					sc_active_scan:1,
 					sc_extra_scan:1;


More information about the svn-src-head mailing list