Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 3 Dec 2016 16:02:53 +0000 (UTC)
From:      Andriy Voskoboinyk <avos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r309481 - head/sys/dev/usb/wlan
Message-ID:  <201612031602.uB3G2r4e082338@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avos
Date: Sat Dec  3 16:02:53 2016
New Revision: 309481
URL: https://svnweb.freebsd.org/changeset/base/309481

Log:
  rsu: fix frame processing in the Rx path (similar to r292207).
  
  - Fill in Rx radiotap header correctly (for every packet in a chain;
  not once per chain).
  - Fix rate / flags fields in Rx radiotap.
  - Add debug messages for discarded frames.
  - Pass received control (< sizeof(struct ieee80211_frame)) frames
  to net80211 (if allowed by device filter; cannot happen yet).
  
  Tested with Asus USB-N10.
  
  Differential Revision:	https://reviews.freebsd.org/D5723

Modified:
  head/sys/dev/usb/wlan/if_rsu.c

Modified: head/sys/dev/usb/wlan/if_rsu.c
==============================================================================
--- head/sys/dev/usb/wlan/if_rsu.c	Sat Dec  3 14:41:53 2016	(r309480)
+++ head/sys/dev/usb/wlan/if_rsu.c	Sat Dec  3 16:02:53 2016	(r309481)
@@ -219,7 +219,10 @@ static void	rsu_rx_multi_event(struct rs
 #if 0
 static int8_t	rsu_get_rssi(struct rsu_softc *, int, void *);
 #endif
-static struct mbuf * rsu_rx_frame(struct rsu_softc *, uint8_t *, int);
+static struct mbuf * rsu_rx_copy_to_mbuf(struct rsu_softc *,
+		    struct r92s_rx_stat *, int);
+static struct ieee80211_node * rsu_rx_frame(struct rsu_softc *, struct mbuf *,
+		    int8_t *);
 static struct mbuf * rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int);
 static struct mbuf *
 		rsu_rxeof(struct usb_xfer *, struct rsu_data *);
@@ -1827,64 +1830,76 @@ rsu_get_rssi(struct rsu_softc *sc, int r
 #endif
 
 static struct mbuf *
-rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen)
+rsu_rx_copy_to_mbuf(struct rsu_softc *sc, struct r92s_rx_stat *stat,
+    int totlen)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_frame *wh;
+	struct mbuf *m;
+	uint32_t rxdw0;
+	int pktlen;
+
+	rxdw0 = le32toh(stat->rxdw0);
+	if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) {
+		RSU_DPRINTF(sc, RSU_DEBUG_RX,
+		    "%s: RX flags error (CRC)\n", __func__);
+		goto fail;
+	}
+
+	pktlen = MS(rxdw0, R92S_RXDW0_PKTLEN);
+	if (__predict_false(pktlen < sizeof (struct ieee80211_frame_ack))) {
+		RSU_DPRINTF(sc, RSU_DEBUG_RX,
+		    "%s: frame is too short: %d\n", __func__, pktlen);
+		goto fail;
+	}
+
+	m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (__predict_false(m == NULL)) {
+		device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n",
+		    __func__);
+		goto fail;
+	}
+
+	/* Finalize mbuf. */
+	memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen);
+	m->m_pkthdr.len = m->m_len = totlen;
+ 
+	return (m);
+fail:
+	counter_u64_add(ic->ic_ierrors, 1);
+	return (NULL);
+}
+
+static struct ieee80211_node *
+rsu_rx_frame(struct rsu_softc *sc, struct mbuf *m, int8_t *rssi_p)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_frame_min *wh;
 	struct r92s_rx_stat *stat;
 	uint32_t rxdw0, rxdw3;
-	struct mbuf *m;
 	uint8_t rate;
 	int infosz;
 
-	stat = (struct r92s_rx_stat *)buf;
+	stat = mtod(m, struct r92s_rx_stat *);
 	rxdw0 = le32toh(stat->rxdw0);
 	rxdw3 = le32toh(stat->rxdw3);
 
-	if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) {
-		counter_u64_add(ic->ic_ierrors, 1);
-		return NULL;
-	}
-	if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) {
-		counter_u64_add(ic->ic_ierrors, 1);
-		return NULL;
-	}
-
 	rate = MS(rxdw3, R92S_RXDW3_RATE);
 	infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
 
 #if 0
 	/* Get RSSI from PHY status descriptor if present. */
 	if (infosz != 0)
-		*rssi = rsu_get_rssi(sc, rate, &stat[1]);
+		*rssi_p = rsu_get_rssi(sc, rate, &stat[1]);
 	else
-		*rssi = 0;
 #endif
-
-	RSU_DPRINTF(sc, RSU_DEBUG_RX,
-	    "%s: Rx frame len=%d rate=%d infosz=%d\n",
-	    __func__, pktlen, rate, infosz);
-
-	m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR);
-	if (__predict_false(m == NULL)) {
-		counter_u64_add(ic->ic_ierrors, 1);
-		return NULL;
-	}
-	/* Hardware does Rx TCP checksum offload. */
-	if (rxdw3 & R92S_RXDW3_TCPCHKVALID) {
-		if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT))
-			m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
-	}
-	wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz);
-	memcpy(mtod(m, uint8_t *), wh, pktlen);
-	m->m_pkthdr.len = m->m_len = pktlen;
+		*rssi_p = 0;
 
 	if (ieee80211_radiotap_active(ic)) {
 		struct rsu_rx_radiotap_header *tap = &sc->sc_rxtap;
 
 		/* Map HW rate index to 802.11 rate. */
-		tap->wr_flags = 2;
-		if (!(rxdw3 & R92S_RXDW3_HTC)) {
+		tap->wr_flags = 0;		/* TODO */
+		if (rate < 12) {
 			switch (rate) {
 			/* CCK. */
 			case  0: tap->wr_rate =   2; break;
@@ -1901,7 +1916,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8
 			case 10: tap->wr_rate =  96; break;
 			case 11: tap->wr_rate = 108; break;
 			}
-		} else if (rate >= 12) {	/* MCS0~15. */
+		} else {			/* MCS0~15. */
 			/* Bit 7 set means HT MCS instead of rate. */
 			tap->wr_rate = 0x80 | (rate - 12);
 		}
@@ -1912,9 +1927,26 @@ rsu_rx_frame(struct rsu_softc *sc, uint8
 		tap->wr_dbm_antsignal = rsu_hwrssi_to_rssi(sc, sc->sc_currssi);
 		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
 		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
+	};
+
+	/* Hardware does Rx TCP checksum offload. */
+	if (rxdw3 & R92S_RXDW3_TCPCHKVALID) {
+		if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT))
+			m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
 	}
 
-	return (m);
+	/* Drop descriptor. */
+	m_adj(m, sizeof(*stat) + infosz);
+	wh = mtod(m, struct ieee80211_frame_min *);
+
+	RSU_DPRINTF(sc, RSU_DEBUG_RX,
+	    "%s: Rx frame len %d, rate %d, infosz %d\n",
+	    __func__, m->m_len, rate, infosz);
+
+	if (m->m_len >= sizeof(*wh))
+		return (ieee80211_find_rxnode(ic, wh));
+
+	return (NULL);
 }
 
 static struct mbuf *
@@ -1925,6 +1957,13 @@ rsu_rx_multi_frame(struct rsu_softc *sc,
 	int totlen, pktlen, infosz, npkts;
 	struct mbuf *m, *m0 = NULL, *prevm = NULL;
 
+	/*
+	 * don't pass packets to the ieee80211 framework if the driver isn't
+	 * RUNNING.
+	 */
+	if (!sc->sc_running)
+		return (NULL);
+
 	/* Get the number of encapsulated frames. */
 	stat = (struct r92s_rx_stat *)buf;
 	npkts = MS(le32toh(stat->rxdw2), R92S_RXDW2_PKTCNT);
@@ -1950,7 +1989,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc,
 			break;
 
 		/* Process 802.11 frame. */
-		m = rsu_rx_frame(sc, buf, pktlen);
+		m = rsu_rx_copy_to_mbuf(sc, stat, totlen);
 		if (m0 == NULL)
 			m0 = m;
 		if (prevm == NULL)
@@ -1998,10 +2037,10 @@ rsu_bulk_rx_callback(struct usb_xfer *xf
 {
 	struct rsu_softc *sc = usbd_xfer_softc(xfer);
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *m = NULL, *next;
 	struct rsu_data *data;
+	int8_t rssi;
 
 	RSU_ASSERT_LOCKED(sc);
 
@@ -2016,10 +2055,6 @@ rsu_bulk_rx_callback(struct usb_xfer *xf
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
-		/*
-		 * XXX TODO: if we have an mbuf list, but then
-		 * we hit data == NULL, what now?
-		 */
 		data = STAILQ_FIRST(&sc->sc_rx_inactive);
 		if (data == NULL) {
 			KASSERT(m == NULL, ("mbuf isn't NULL"));
@@ -2035,18 +2070,16 @@ tr_setup:
 		 * ieee80211_input() because here is at the end of a USB
 		 * callback and safe to unlock.
 		 */
-		RSU_UNLOCK(sc);
 		while (m != NULL) {
-			int rssi;
+			next = m->m_next;
+			m->m_next = NULL;
+
+			ni = rsu_rx_frame(sc, m, &rssi);
 
 			/* Cheat and get the last calibrated RSSI */
 			rssi = rsu_hwrssi_to_rssi(sc, sc->sc_currssi);
+			RSU_UNLOCK(sc);
 
-			next = m->m_next;
-			m->m_next = NULL;
-			wh = mtod(m, struct ieee80211_frame *);
-			ni = ieee80211_find_rxnode(ic,
-			    (struct ieee80211_frame_min *)wh);
 			if (ni != NULL) {
 				if (ni->ni_flags & IEEE80211_NODE_HT)
 					m->m_flags |= M_AMPDU;
@@ -2054,9 +2087,10 @@ tr_setup:
 				ieee80211_free_node(ni);
 			} else
 				(void)ieee80211_input_all(ic, m, rssi, -96);
+
+			RSU_LOCK(sc);
 			m = next;
 		}
-		RSU_LOCK(sc);
 		break;
 	default:
 		/* needs it to the inactive queue due to a error. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612031602.uB3G2r4e082338>