From owner-svn-src-all@freebsd.org Tue Nov 10 00:12:02 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 6CAC3A2A7AB; Tue, 10 Nov 2015 00:12:02 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 424151CD3; Tue, 10 Nov 2015 00:12:02 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tAA0C1bB096813; Tue, 10 Nov 2015 00:12:01 GMT (envelope-from avos@FreeBSD.org) Received: (from avos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tAA0C1mI096810; Tue, 10 Nov 2015 00:12:01 GMT (envelope-from avos@FreeBSD.org) Message-Id: <201511100012.tAA0C1mI096810@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avos set sender to avos@FreeBSD.org using -f From: Andriy Voskoboinyk Date: Tue, 10 Nov 2015 00:12:01 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r290631 - head/sys/dev/usb/wlan X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Nov 2015 00:12:02 -0000 Author: avos Date: Tue Nov 10 00:12:00 2015 New Revision: 290631 URL: https://svnweb.freebsd.org/changeset/base/290631 Log: urtwn(4): add HOSTAP mode support. Tested with RTL8188EU, HOSTAP and STA modes Reviewed by: kevlo Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D4034 Modified: head/sys/dev/usb/wlan/if_urtwn.c head/sys/dev/usb/wlan/if_urtwnreg.h head/sys/dev/usb/wlan/if_urtwnvar.h Modified: head/sys/dev/usb/wlan/if_urtwn.c ============================================================================== --- head/sys/dev/usb/wlan/if_urtwn.c Mon Nov 9 23:46:13 2015 (r290630) +++ head/sys/dev/usb/wlan/if_urtwn.c Tue Nov 10 00:12:00 2015 (r290631) @@ -221,7 +221,15 @@ static int urtwn_read_chipid(struct urt static void urtwn_read_rom(struct urtwn_softc *); static void urtwn_r88e_read_rom(struct urtwn_softc *); static int urtwn_ra_init(struct urtwn_softc *); -static void urtwn_tsf_sync_enable(struct urtwn_softc *); +static void urtwn_init_beacon(struct urtwn_softc *, + struct urtwn_vap *); +static int urtwn_setup_beacon(struct urtwn_softc *, + struct ieee80211_node *); +static void urtwn_update_beacon(struct ieee80211vap *, int); +static int urtwn_tx_beacon(struct urtwn_softc *sc, + struct urtwn_vap *); +static void urtwn_tsf_sync_enable(struct urtwn_softc *, + struct ieee80211vap *); static void urtwn_set_led(struct urtwn_softc *, int, int); static void urtwn_set_mode(struct urtwn_softc *, uint8_t); static int urtwn_newstate(struct ieee80211vap *, @@ -441,6 +449,7 @@ urtwn_attach(device_t self) ic->ic_caps = IEEE80211_C_STA /* station mode */ | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_HOSTAP /* hostap mode */ | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_SHSLOT /* short slot time supported */ | IEEE80211_C_BGSCAN /* capable of bg scanning */ @@ -565,6 +574,7 @@ urtwn_vap_create(struct ieee80211com *ic const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { + struct urtwn_softc *sc = ic->ic_softc; struct urtwn_vap *uvp; struct ieee80211vap *vap; @@ -582,9 +592,13 @@ urtwn_vap_create(struct ieee80211com *ic return (NULL); } + if (opmode == IEEE80211_M_HOSTAP) + urtwn_init_beacon(sc, uvp); + /* override state transition machine */ uvp->newstate = vap->iv_newstate; vap->iv_newstate = urtwn_newstate; + vap->iv_update_beacon = urtwn_update_beacon; /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, @@ -597,7 +611,12 @@ static void urtwn_vap_delete(struct ieee80211vap *vap) { struct urtwn_vap *uvp = URTWN_VAP(vap); + enum ieee80211_opmode opmode = vap->iv_opmode; + if (opmode == IEEE80211_M_HOSTAP) { + if (uvp->bcn_mbuf != NULL) + m_freem(uvp->bcn_mbuf); + } ieee80211_vap_detach(vap); free(uvp, M_80211_VAP); } @@ -831,7 +850,8 @@ urtwn_txeof(struct urtwn_softc *sc, stru URTWN_ASSERT_LOCKED(sc); - ieee80211_tx_complete(data->ni, data->m, status); + if (data->ni != NULL) /* not a beacon frame */ + ieee80211_tx_complete(data->ni, data->m, status); data->ni = NULL; data->m = NULL; @@ -1477,10 +1497,144 @@ urtwn_ra_init(struct urtwn_softc *sc) } static void -urtwn_tsf_sync_enable(struct urtwn_softc *sc) +urtwn_init_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) { - urtwn_write_1(sc, R92C_BCN_CTRL, - urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); + struct r92c_tx_desc *txd = &uvp->bcn_desc; + + txd->txdw0 = htole32( + SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | R92C_TXDW0_BMCAST | + R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); + txd->txdw1 = htole32( + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) | + SM(R92C_TXDW1_RAID, R92C_RAID_11B)); + + if (sc->chip & URTWN_CHIP_88E) + txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC)); + else + txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC)); + + txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); + txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, URTWN_RIDX_CCK1)); + txd->txdseq = htole16(R92C_TXDSEQ_HWSEQ_EN); +} + +static int +urtwn_setup_beacon(struct urtwn_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct urtwn_vap *uvp = URTWN_VAP(vap); + struct mbuf *m; + int error; + + URTWN_ASSERT_LOCKED(sc); + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return (EINVAL); + + m = ieee80211_beacon_alloc(ni); + if (m == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + return (ENOMEM); + } + + if (uvp->bcn_mbuf != NULL) + m_freem(uvp->bcn_mbuf); + + uvp->bcn_mbuf = m; + + if ((error = urtwn_tx_beacon(sc, uvp)) != 0) + return (error); + + /* XXX bcnq stuck workaround */ + if ((error = urtwn_tx_beacon(sc, uvp)) != 0) + return (error); + + return (0); +} + +static void +urtwn_update_beacon(struct ieee80211vap *vap, int item) +{ + struct urtwn_softc *sc = vap->iv_ic->ic_softc; + struct urtwn_vap *uvp = URTWN_VAP(vap); + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct ieee80211_node *ni = vap->iv_bss; + int mcast = 0; + + URTWN_LOCK(sc); + if (uvp->bcn_mbuf == NULL) { + uvp->bcn_mbuf = ieee80211_beacon_alloc(ni); + if (uvp->bcn_mbuf == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + URTWN_UNLOCK(sc); + return; + } + } + URTWN_UNLOCK(sc); + + if (item == IEEE80211_BEACON_TIM) + mcast = 1; /* XXX */ + + setbit(bo->bo_flags, item); + ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast); + + URTWN_LOCK(sc); + urtwn_tx_beacon(sc, uvp); + URTWN_UNLOCK(sc); +} + +/* + * Push a beacon frame into the chip. Beacon will + * be repeated by the chip every R92C_BCN_INTERVAL. + */ +static int +urtwn_tx_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) +{ + struct r92c_tx_desc *desc = &uvp->bcn_desc; + struct urtwn_data *bf; + + URTWN_ASSERT_LOCKED(sc); + + bf = urtwn_getbuf(sc); + if (bf == NULL) + return (ENOMEM); + + memcpy(bf->buf, desc, sizeof(*desc)); + urtwn_tx_start(sc, uvp->bcn_mbuf, IEEE80211_FC0_TYPE_MGT, bf); + + sc->sc_txtimer = 5; + callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); + + return (0); +} + +static void +urtwn_tsf_sync_enable(struct urtwn_softc *sc, struct ieee80211vap *vap) +{ + /* Reset TSF. */ + urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); + + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + /* Enable TSF synchronization. */ + urtwn_write_1(sc, R92C_BCN_CTRL, + urtwn_read_1(sc, R92C_BCN_CTRL) & + ~R92C_BCN_CTRL_DIS_TSF_UDT0); + break; + case IEEE80211_M_HOSTAP: + /* Enable beaconing. */ + urtwn_write_1(sc, R92C_MBID_NUM, + urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); + urtwn_write_1(sc, R92C_BCN_CTRL, + urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); + break; + default: + device_printf(sc->sc_dev, "undefined opmode %d\n", + vap->iv_opmode); + return; + } } static void @@ -1528,6 +1682,9 @@ urtwn_newstate(struct ieee80211vap *vap, struct urtwn_softc *sc = ic->ic_softc; struct ieee80211_node *ni; enum ieee80211_state ostate; + uint32_t reg; + uint8_t mode; + int error = 0; ostate = vap->iv_state; DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], @@ -1547,14 +1704,18 @@ urtwn_newstate(struct ieee80211vap *vap, /* Stop Rx of data frames. */ urtwn_write_2(sc, R92C_RXFLTMAP2, 0); - /* Rest TSF. */ - urtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03); - /* Disable TSF synchronization. */ urtwn_write_1(sc, R92C_BCN_CTRL, - urtwn_read_1(sc, R92C_BCN_CTRL) | + (urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN) | R92C_BCN_CTRL_DIS_TSF_UDT0); + /* Disable beaconing. */ + urtwn_write_1(sc, R92C_MBID_NUM, + urtwn_read_1(sc, R92C_MBID_NUM) & ~R92C_MBID_TXBCN_RPT0); + + /* Reset TSF. */ + urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); + /* Reset EDCA parameters. */ urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); @@ -1583,8 +1744,31 @@ urtwn_newstate(struct ieee80211vap *vap, } ni = ieee80211_ref_node(vap->iv_bss); + + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || + ni->ni_chan == IEEE80211_CHAN_ANYC) { + device_printf(sc->sc_dev, + "%s: could not move to RUN state\n", __func__); + error = EINVAL; + goto end_run; + } + + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + mode = R92C_MSR_INFRA; + break; + case IEEE80211_M_HOSTAP: + mode = R92C_MSR_AP; + break; + default: + device_printf(sc->sc_dev, "undefined opmode %d\n", + vap->iv_opmode); + error = EINVAL; + goto end_run; + } + /* Set media status to 'Associated'. */ - urtwn_set_mode(sc, R92C_MSR_INFRA); + urtwn_set_mode(sc, mode); /* Set BSSID. */ urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0])); @@ -1606,13 +1790,28 @@ urtwn_newstate(struct ieee80211vap *vap, /* Allow Rx from our BSSID only. */ 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); + reg = urtwn_read_4(sc, R92C_RCR); + + if (vap->iv_opmode != IEEE80211_M_HOSTAP) + reg |= R92C_RCR_CBSSID_DATA; + + reg |= R92C_RCR_CBSSID_BCN; + + urtwn_write_4(sc, R92C_RCR, reg); + } + + if (vap->iv_opmode == IEEE80211_M_HOSTAP) { + error = urtwn_setup_beacon(sc, ni); + if (error != 0) { + device_printf(sc->sc_dev, + "unable to push beacon into the chip, " + "error %d\n", error); + goto end_run; + } } /* Enable TSF synchronization. */ - urtwn_tsf_sync_enable(sc); + urtwn_tsf_sync_enable(sc, vap); urtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); urtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); @@ -1634,14 +1833,17 @@ urtwn_newstate(struct ieee80211vap *vap, /* Reset temperature calibration state machine. */ sc->thcal_state = 0; sc->thcal_lctemp = 0; + +end_run: ieee80211_free_node(ni); break; default: break; } + URTWN_UNLOCK(sc); IEEE80211_LOCK(ic); - return(uvp->newstate(vap, nstate, arg)); + return (error != 0 ? error : uvp->newstate(vap, nstate, arg)); } static void @@ -2791,11 +2993,25 @@ urtwn_rxfilter_init(struct urtwn_softc * /* Filter for management frames. */ filter = 0x7f3f; - if (vap->iv_opmode == IEEE80211_M_STA) { + switch (vap->iv_opmode) { + case 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)); + break; + case IEEE80211_M_HOSTAP: + filter &= ~( + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_BEACON)); + break; + case IEEE80211_M_MONITOR: + break; + default: + device_printf(sc->sc_dev, "%s: undefined opmode %d\n", + __func__, vap->iv_opmode); + break; } urtwn_write_2(sc, R92C_RXFLTMAP0, filter); @@ -3172,7 +3388,10 @@ urtwn_set_promisc(struct urtwn_softc *sc if (vap->iv_state == IEEE80211_S_RUN) { switch (vap->iv_opmode) { case IEEE80211_M_STA: - mask2 |= R92C_RCR_CBSSID_BCN | R92C_RCR_CBSSID_DATA; + mask2 |= R92C_RCR_CBSSID_DATA; + /* FALLTHROUGH */ + case IEEE80211_M_HOSTAP: + mask2 |= R92C_RCR_CBSSID_BCN; break; default: device_printf(sc->sc_dev, "%s: undefined opmode %d\n", Modified: head/sys/dev/usb/wlan/if_urtwnreg.h ============================================================================== --- head/sys/dev/usb/wlan/if_urtwnreg.h Mon Nov 9 23:46:13 2015 (r290630) +++ head/sys/dev/usb/wlan/if_urtwnreg.h Tue Nov 10 00:12:00 2015 (r290631) @@ -495,6 +495,14 @@ #define R92C_BCN_CTRL_EN_BCN 0x08 #define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10 +/* Bits for R92C_MBID_NUM. */ +#define R92C_MBID_TXBCN_RPT0 0x08 +#define R92C_MBID_TXBCN_RPT1 0x10 + +/* Bits for R92C_DUAL_TSF_RST. */ +#define R92C_DUAL_TSF_RST0 0x01 +#define R92C_DUAL_TSF_RST1 0x02 + /* Bits for R92C_APSD_CTRL. */ #define R92C_APSD_CTRL_OFF 0x40 #define R92C_APSD_CTRL_OFF_STATUS 0x80 Modified: head/sys/dev/usb/wlan/if_urtwnvar.h ============================================================================== --- head/sys/dev/usb/wlan/if_urtwnvar.h Mon Nov 9 23:46:13 2015 (r290630) +++ head/sys/dev/usb/wlan/if_urtwnvar.h Tue Nov 10 00:12:00 2015 (r290631) @@ -89,6 +89,9 @@ struct urtwn_fw_info { struct urtwn_vap { struct ieee80211vap vap; + struct r92c_tx_desc bcn_desc; + struct mbuf *bcn_mbuf; + int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); };