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