Date: Sat, 10 Dec 2016 18:47:14 +0000 (UTC) From: Andriy Voskoboinyk <avos@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r309825 - head/sys/dev/usb/wlan Message-ID: <201612101847.uBAIlEFb094635@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612101847.uBAIlEFb094635>