Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152617149
D4034.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D4034.diff
View Options
Index: head/sys/dev/usb/wlan/if_urtwn.c
===================================================================
--- head/sys/dev/usb/wlan/if_urtwn.c
+++ head/sys/dev/usb/wlan/if_urtwn.c
@@ -221,7 +221,15 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
}
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 @@
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 @@
/* 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 @@
}
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 @@
/* 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 @@
/* 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 @@
/* 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 @@
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",
Index: head/sys/dev/usb/wlan/if_urtwnreg.h
===================================================================
--- head/sys/dev/usb/wlan/if_urtwnreg.h
+++ head/sys/dev/usb/wlan/if_urtwnreg.h
@@ -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
Index: head/sys/dev/usb/wlan/if_urtwnvar.h
===================================================================
--- head/sys/dev/usb/wlan/if_urtwnvar.h
+++ head/sys/dev/usb/wlan/if_urtwnvar.h
@@ -89,6 +89,9 @@
struct urtwn_vap {
struct ieee80211vap vap;
+ struct r92c_tx_desc bcn_desc;
+ struct mbuf *bcn_mbuf;
+
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 17, 1:03 AM (12 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31631605
Default Alt Text
D4034.diff (11 KB)
Attached To
Mode
D4034: urtwn(4): add HOSTAP mode support
Attached
Detach File
Event Timeline
Log In to Comment