urtwn and hostap
Matthew Grooms
mgrooms at shrew.net
Wed Sep 16 05:46:43 UTC 2015
Hey wireless folks,
I wanted to setup a Raspberry Pi as a FreeBSD AP and purchased a picked
up a few Edimax 802.11 adapters to play with. Unfortunately these aren't
supported in hostap mode. As it turns out these Edimax adapters use the
RTL8188CUS chipset so I poked around the net and noticed that Linux does
support the host AP feature with it's RTL8188CUS driver. I was also able
to find a patch for OpenBSD that added support for the RTL8188EU chipset
to the urtwn driver ...
http://marc.info/?l=openbsd-tech&m=143577648117514&w=2
So I ordered one of these which arrived from China a few weeks later ...
http://www.amazon.com/gp/product/B00L28AN88?psc=1&redirect=true&ref_=oh_aui_detailpage_o05_s00
Next I took a stab at porting the patch to FreeBSD. With the attached
patch applied, I was able to setup a wlan0 device with the hostap
feature. After bridging it with the LAN I could associate with my
android phone, obtain an IP address via DHCP, browse a few web pages and
watch all the packets pass through the bridge. Sadly, when I attempted
to destroy the wlan0 device I got a kernel panic. The screenshot for
that is also attached and I'm not sure if I'm going to be able to figure
this one out without some help. I'm pretty out of my element here. I
assume it's happening in ieee80211_free_node() when
IEEE80211_NODE_LOCK() is called. To be clear, the crash only occurs when
the adapter is configured in hostap mode with the patch applied. Anyone
have any suggestions as to what I should be looking at to prevent this
crash?
If I can get this working for the RTL8188EU, I'll also take a stab at
getting the RTL8188CUS chipset working in hostap mode. That is, assuming
I can glean enough info from drivers that support this feature on other
open source platforms. It appears to be extremely popular with the
Raspberry PI crowd ...
http://www.amazon.com/Edimax-EW-7811Un-150Mbps-Raspberry-Supports/dp/B003MTTJOY
Thanks in advance,
-Matthew
-------------- next part --------------
Index: dev/usb/wlan/if_urtwn.c
===================================================================
--- dev/usb/wlan/if_urtwn.c (revision 287342)
+++ dev/usb/wlan/if_urtwn.c (working copy)
@@ -181,6 +181,8 @@
static struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *,
int *, int8_t *);
static void urtwn_txeof(struct usb_xfer *, struct urtwn_data *);
+int urtwn_txbcn(struct ieee80211vap *vap,
+ struct ieee80211_node *);
static int urtwn_alloc_list(struct urtwn_softc *,
struct urtwn_data[], int, int);
static int urtwn_alloc_rx_list(struct urtwn_softc *);
@@ -436,6 +438,10 @@
| IEEE80211_C_WPA /* 802.11i */
;
+ if (sc->chip & URTWN_CHIP_88E)
+ ic->ic_caps |=
+ IEEE80211_C_HOSTAP; /* HostAp mode supported */
+
bands = 0;
setbit(&bands, IEEE80211_MODE_11B);
setbit(&bands, IEEE80211_MODE_11G);
@@ -857,6 +863,36 @@
sc->sc_txtimer = 0;
}
+/*
+ * Push a beacon frame into the chip and check if it was accepted. Beacon will
+ * be repeated by the chip every R92C_BCN_INTERVAL.
+ */
+int
+urtwn_txbcn(struct ieee80211vap *vap, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct urtwn_softc *sc = ic->ic_softc;
+ struct urtwn_data *bf;
+ struct mbuf *m;
+
+ m = ieee80211_beacon_alloc(ni, &URTWN_VAP(vap)->bo);
+
+ bf = urtwn_getbuf(sc);
+ if (bf == NULL) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+
+ if (urtwn_tx_start(sc, ni, m, bf) != 0) {
+ STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
+ return (EIO);
+ }
+
+ sc->sc_txtimer = 5;
+
+ return (0);
+}
+
static void
urtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
{
@@ -1466,6 +1502,7 @@
struct ieee80211_node *ni;
enum ieee80211_state ostate;
uint32_t reg;
+ int error;
ostate = vap->iv_state;
DPRINTF("%s -> %s\n", ieee80211_state_name[ostate],
@@ -1553,23 +1590,68 @@
}
ni = ieee80211_ref_node(vap->iv_bss);
- /* Set media status to 'Associated'. */
- reg = urtwn_read_4(sc, R92C_CR);
- reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
- urtwn_write_4(sc, R92C_CR, reg);
- /* Set BSSID. */
- urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0]));
- urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4]));
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ /* Set BSSID. */
+ urtwn_write_4(sc, R92C_BSSID + 0,
+ LE_READ_4(&ni->ni_bssid[0]));
+ urtwn_write_4(sc, R92C_BSSID + 4,
+ LE_READ_2(&ni->ni_bssid[4]));
- if (ic->ic_curmode == IEEE80211_MODE_11B)
- urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
- else /* 802.11b/g */
- urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
+ else /* 802.11b/g */
+ urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
- /* Enable Rx of data frames. */
- urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+ /* Enable Rx of data frames. */
+ urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+ /* Allow Rx from our BSSID only. */
+ urtwn_write_4(sc, R92C_RCR, urtwn_read_4(sc, R92C_RCR) |
+ R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
+
+ /* Set media status to 'Associated'. */
+ reg = urtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
+ urtwn_write_4(sc, R92C_CR, reg);
+ }
+
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ /* Set media status to 'AP'. */
+ reg = urtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_AP);
+ urtwn_write_4(sc, R92C_CR, reg);
+
+ /* Set BSSID. */
+ urtwn_write_4(sc, R92C_BSSID + 0,
+ LE_READ_4(&ni->ni_bssid[0]));
+ urtwn_write_4(sc, R92C_BSSID + 4,
+ LE_READ_2(&ni->ni_bssid[4]));
+
+ /*
+ * If 3rd or 4th bits are set to zero chip will stop
+ * repeating beacon after first transmission for port0
+ * and port1 respectively. This will cause STAs to
+ * disconnect after short period of time.
+ */
+ reg = urtwn_read_1(sc, R92C_MBID_NUM);
+ reg |= 0x8;
+ reg |= 0x10;
+ urtwn_write_1(sc, R92C_MBID_NUM, reg);
+
+ /* Invalidate cam entries */
+ urtwn_cam_init(sc);
+
+ /* Set chan/bw */
+ urtwn_set_chan(sc, ic->ic_curchan, NULL);
+
+ /* Push beacon frame into the chip */
+ error = urtwn_txbcn(vap, ni);
+ if (error != 0)
+ printf("%s: unable to push beacon into the"
+ " chip\n", device_get_nameunit(sc->sc_dev));
+ }
+
/* Flush all AC queues. */
urtwn_write_1(sc, R92C_TXPAUSE, 0);
@@ -1576,11 +1658,6 @@
/* Set beacon interval. */
urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
- /* Allow Rx from our BSSID only. */
- urtwn_write_4(sc, R92C_RCR,
- urtwn_read_4(sc, R92C_RCR) |
- R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
-
/* Enable TSF synchronization. */
urtwn_tsf_sync_enable(sc);
@@ -1754,7 +1831,7 @@
struct ieee80211vap *vap = ni->ni_vap;
struct usb_xfer *xfer;
struct r92c_tx_desc *txd;
- uint8_t raid, type;
+ uint8_t raid, type, subtype;
uint16_t sum;
int i, hasqos, xferlen;
struct usb_xfer *urtwn_pipes[4] = {
@@ -1771,6 +1848,7 @@
*/
wh = mtod(m0, struct ieee80211_frame *);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
k = ieee80211_crypto_encap(ni, m0);
@@ -1819,7 +1897,7 @@
if (sc->chip & URTWN_CHIP_88E) {
txd->txdw1 |= htole32(
SM(R88E_TXDW1_MACID, URTWN_MACID_BSS) |
- SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |
+ SM(R92C_TXDW1_QSEL, R88E_TXDW1_QSEL_BE) |
SM(R92C_TXDW1_RAID, raid));
txd->txdw2 |= htole32(R88E_TXDW2_AGGBK);
} else {
@@ -1843,9 +1921,20 @@
/* Send data at OFDM54. */
txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11));
} else {
+ /*
+ * If beacon frame is pushed into wrong queue, the chip won't
+ * start repeating it.
+ */
+ if (subtype == IEEE80211_FC0_SUBTYPE_BEACON &&
+ sc->chip & URTWN_CHIP_88E)
+ txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL,
+ R88E_TXDW1_QSEL_MGNT));
+ else
+ txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL,
+ R92C_TXDW1_QSEL_MGNT));
+
txd->txdw1 |= htole32(
SM(R92C_TXDW1_MACID, 0) |
- SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) |
SM(R92C_TXDW1_RAID, R92C_RAID_11B));
/* Force CCK1. */
Index: dev/usb/wlan/if_urtwnreg.h
===================================================================
--- dev/usb/wlan/if_urtwnreg.h (revision 287342)
+++ dev/usb/wlan/if_urtwnreg.h (working copy)
@@ -1019,7 +1019,9 @@
#define R92C_TXDW1_QSEL_M 0x00001f00
#define R92C_TXDW1_QSEL_S 8
#define R92C_TXDW1_QSEL_BE 0x00
+#define R88E_TXDW1_QSEL_BE 0x03
#define R92C_TXDW1_QSEL_MGNT 0x12
+#define R88E_TXDW1_QSEL_MGNT 0x10
#define R92C_TXDW1_RAID_M 0x000f0000
#define R92C_TXDW1_RAID_S 16
#define R92C_TXDW1_CIPHER_M 0x00c00000
More information about the freebsd-wireless
mailing list