mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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
This commit is contained in:
parent
3aedf2e3b6
commit
337bcd0ac2
3 changed files with 247 additions and 17 deletions
|
|
@ -221,7 +221,15 @@ static int urtwn_read_chipid(struct urtwn_softc *);
|
|||
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 char name[IFNAMSIZ], int unit,
|
|||
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, const char name[IFNAMSIZ], int unit,
|
|||
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, struct urtwn_data *data, int status)
|
|||
|
||||
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, enum ieee80211_state nstate, int arg)
|
|||
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, enum ieee80211_state nstate, int arg)
|
|||
/* 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, enum ieee80211_state nstate, int arg)
|
|||
}
|
||||
|
||||
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, enum ieee80211_state nstate, int arg)
|
|||
|
||||
/* 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, enum ieee80211_state nstate, int arg)
|
|||
/* 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 *sc)
|
|||
|
||||
/* 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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue