svn commit: r292207 - head/sys/dev/usb/wlan

Andriy Voskoboinyk avos at FreeBSD.org
Mon Dec 14 13:05:17 UTC 2015


Author: avos
Date: Mon Dec 14 13:05:16 2015
New Revision: 292207
URL: https://svnweb.freebsd.org/changeset/base/292207

Log:
  urtwn: fix frame processing in the Rx path.
  
  Currently, in case when npkts >= 2, RSSI and Rx radiotap fields
  will be overridden by the next packet. As a result, every packet
  from this chain will use the same RSSI / radiotap data.
  
  After this change, RSSI and radiotap structure will be filled
  for every frame right before ieee80211_input() call.
  
  Tested with RTL8188EU / RTL8188CUS, STA and MONITOR modes.
  
  Reviewed by:	kevlo
  Approved by:	adrian (mentor)
  Differential Revision:	https://reviews.freebsd.org/D4487

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

Modified: head/sys/dev/usb/wlan/if_urtwn.c
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwn.c	Mon Dec 14 13:01:51 2015	(r292206)
+++ head/sys/dev/usb/wlan/if_urtwn.c	Mon Dec 14 13:05:16 2015	(r292207)
@@ -182,14 +182,15 @@ static struct ieee80211vap *urtwn_vap_cr
                     const uint8_t [IEEE80211_ADDR_LEN],
                     const uint8_t [IEEE80211_ADDR_LEN]);
 static void		urtwn_vap_delete(struct ieee80211vap *);
-static struct mbuf *	urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int,
-			    int *);
-static struct mbuf *	urtwn_report_intr(struct usb_xfer *, struct urtwn_data *,
-			    int *, int8_t *);
-static struct mbuf *	urtwn_rxeof(struct urtwn_softc *, uint8_t *, int,
-			    int *, int8_t *);
+static struct mbuf *	urtwn_rx_copy_to_mbuf(struct urtwn_softc *,
+			    struct r92c_rx_stat *, int);
+static struct mbuf *	urtwn_report_intr(struct usb_xfer *,
+			    struct urtwn_data *);
+static struct mbuf *	urtwn_rxeof(struct urtwn_softc *, uint8_t *, int);
 static void		urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *,
 			    void *);
+static struct ieee80211_node *urtwn_rx_frame(struct urtwn_softc *,
+			    struct mbuf *, int8_t *);
 static void		urtwn_txeof(struct urtwn_softc *, struct urtwn_data *,
 			    int);
 static int		urtwn_alloc_list(struct urtwn_softc *,
@@ -715,16 +716,13 @@ urtwn_vap_delete(struct ieee80211vap *va
 }
 
 static struct mbuf *
-urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p)
+urtwn_rx_copy_to_mbuf(struct urtwn_softc *sc, struct r92c_rx_stat *stat,
+    int totlen)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_frame *wh;
 	struct mbuf *m;
-	struct r92c_rx_stat *stat;
-	uint32_t rxdw0, rxdw3;
-	uint8_t rate, cipher;
-	int8_t rssi = 0;
-	int infosz;
+	uint32_t rxdw0;
+	int pktlen;
 
 	/*
 	 * don't pass packets to the ieee80211 framework if the driver isn't
@@ -733,87 +731,49 @@ urtwn_rx_frame(struct urtwn_softc *sc, u
 	if (!(sc->sc_flags & URTWN_RUNNING))
 		return (NULL);
 
-	stat = (struct r92c_rx_stat *)buf;
 	rxdw0 = le32toh(stat->rxdw0);
-	rxdw3 = le32toh(stat->rxdw3);
-
 	if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) {
 		/*
 		 * This should not happen since we setup our Rx filter
 		 * to not receive these frames.
 		 */
-		counter_u64_add(ic->ic_ierrors, 1);
-		return (NULL);
-	}
-	if (pktlen < sizeof(struct ieee80211_frame_ack) ||
-	    pktlen > MCLBYTES) {
-		counter_u64_add(ic->ic_ierrors, 1);
-		return (NULL);
+		DPRINTFN(6, "RX flags error (%s)\n",
+		    rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV");
+		goto fail;
 	}
 
-	rate = MS(rxdw3, R92C_RXDW3_RATE);
-	cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
-	infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+	pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+	if (pktlen < sizeof(struct ieee80211_frame_ack)) {
+		DPRINTFN(6, "frame too short: %d\n", pktlen);
+		goto fail;
+	}
 
-	/* Get RSSI from PHY status descriptor if present. */
-	if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
-		if (sc->chip & URTWN_CHIP_88E)
-			rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]);
-		else
-			rssi = urtwn_get_rssi(sc, rate, &stat[1]);
-		/* Update our average RSSI. */
-		urtwn_update_avgrssi(sc, rate, rssi);
+	if (__predict_false(totlen > MCLBYTES)) {
+		/* convert to m_getjcl if this happens */
+		device_printf(sc->sc_dev, "%s: frame too long: %d (%d)\n",
+		    __func__, pktlen, totlen);
+		goto fail;
 	}
 
 	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
-	if (m == NULL) {
-		device_printf(sc->sc_dev, "could not create RX mbuf\n");
-		return (NULL);
+	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[1] + infosz, pktlen);
- 	m->m_pkthdr.len = m->m_len = pktlen; 
-	wh = mtod(m, struct ieee80211_frame *);
-
-	if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
-	    cipher != R92C_CAM_ALGO_NONE) {
-		m->m_flags |= M_WEP;
-	}
-
-	if (ieee80211_radiotap_active(ic)) {
-		struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
-
-		tap->wr_flags = 0;
-
-		urtwn_get_tsf(sc, &tap->wr_tsft);
-		if (__predict_false(le32toh((uint32_t)tap->wr_tsft) <
-		                    le32toh(stat->rxdw5))) {
-			tap->wr_tsft = le32toh(tap->wr_tsft  >> 32) - 1;
-			tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32;
-		} else
-			tap->wr_tsft &= 0xffffffff00000000;
-		tap->wr_tsft += stat->rxdw5;
-
-		/* Map HW rate index to 802.11 rate. */
-		if (!(rxdw3 & R92C_RXDW3_HT)) {
-			tap->wr_rate = ridx2rate[rate];
-		} else if (rate >= 12) {	/* MCS0~15. */
-			/* Bit 7 set means HT MCS instead of rate. */
-			tap->wr_rate = 0x80 | (rate - 12);
-		}
-		tap->wr_dbm_antsignal = rssi;
-		tap->wr_dbm_antnoise = URTWN_NOISE_FLOOR;
-	}
-
-	*rssi_p = rssi;
-
+	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 mbuf *
-urtwn_report_intr(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi,
-    int8_t *nf)
+urtwn_report_intr(struct usb_xfer *xfer, struct urtwn_data *data)
 {
 	struct urtwn_softc *sc = data->sc;
 	struct ieee80211com *ic = &sc->sc_ic;
@@ -836,7 +796,7 @@ urtwn_report_intr(struct usb_xfer *xfer,
 
 		switch (report_sel) {
 		case R88E_RXDW3_RPT_RX:
-			return (urtwn_rxeof(sc, buf, len, rssi, nf));
+			return (urtwn_rxeof(sc, buf, len));
 		case R88E_RXDW3_RPT_TX1:
 			urtwn_r88e_ratectl_tx_complete(sc, &stat[1]);
 			break;
@@ -845,14 +805,13 @@ urtwn_report_intr(struct usb_xfer *xfer,
 			break;
 		}
 	} else
-		return (urtwn_rxeof(sc, buf, len, rssi, nf));
+		return (urtwn_rxeof(sc, buf, len));
 
 	return (NULL);
 }
 
 static struct mbuf *
-urtwn_rxeof(struct urtwn_softc *sc, uint8_t *buf, int len, int *rssi,
-    int8_t *nf)
+urtwn_rxeof(struct urtwn_softc *sc, uint8_t *buf, int len)
 {
 	struct r92c_rx_stat *stat;
 	struct mbuf *m, *m0 = NULL, *prevm = NULL;
@@ -882,7 +841,7 @@ urtwn_rxeof(struct urtwn_softc *sc, uint
 		if (totlen > len)
 			break;
 
-		m = urtwn_rx_frame(sc, buf, pktlen, rssi);
+		m = urtwn_rx_copy_to_mbuf(sc, stat, totlen);
 		if (m0 == NULL)
 			m0 = m;
 		if (prevm == NULL)
@@ -930,17 +889,86 @@ urtwn_r88e_ratectl_tx_complete(struct ur
 	URTWN_NT_UNLOCK(sc);
 }
 
+static struct ieee80211_node *
+urtwn_rx_frame(struct urtwn_softc *sc, struct mbuf *m, int8_t *rssi_p)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_frame_min *wh;
+	struct r92c_rx_stat *stat;
+	uint32_t rxdw0, rxdw3;
+	uint8_t rate, cipher;
+	int8_t rssi = URTWN_NOISE_FLOOR + 1;
+	int infosz;
+
+	stat = mtod(m, struct r92c_rx_stat *);
+	rxdw0 = le32toh(stat->rxdw0);
+	rxdw3 = le32toh(stat->rxdw3);
+
+	rate = MS(rxdw3, R92C_RXDW3_RATE);
+	cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
+	infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+
+	/* Get RSSI from PHY status descriptor if present. */
+	if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
+		if (sc->chip & URTWN_CHIP_88E)
+			rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]);
+		else
+			rssi = urtwn_get_rssi(sc, rate, &stat[1]);
+		/* Update our average RSSI. */
+		urtwn_update_avgrssi(sc, rate, rssi);
+	}
+
+	if (ieee80211_radiotap_active(ic)) {
+		struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
+
+		tap->wr_flags = 0;
+
+		urtwn_get_tsf(sc, &tap->wr_tsft);
+		if (__predict_false(le32toh((uint32_t)tap->wr_tsft) <
+				    le32toh(stat->rxdw5))) {
+			tap->wr_tsft = le32toh(tap->wr_tsft  >> 32) - 1;
+			tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32;
+		} else
+			tap->wr_tsft &= 0xffffffff00000000;
+		tap->wr_tsft += stat->rxdw5;
+
+		/* Map HW rate index to 802.11 rate. */
+		if (!(rxdw3 & R92C_RXDW3_HT)) {
+			tap->wr_rate = ridx2rate[rate];
+		} else if (rate >= 12) {	/* MCS0~15. */
+			/* Bit 7 set means HT MCS instead of rate. */
+			tap->wr_rate = 0x80 | (rate - 12);
+		}
+		tap->wr_dbm_antsignal = rssi;
+		tap->wr_dbm_antnoise = URTWN_NOISE_FLOOR;
+	}
+
+	*rssi_p = rssi;
+
+	/* Drop descriptor. */
+	m_adj(m, sizeof(*stat) + infosz);
+	wh = mtod(m, struct ieee80211_frame_min *);
+
+	if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+	    cipher != R92C_CAM_ALGO_NONE) {
+		m->m_flags |= M_WEP;
+	}
+
+	if (m->m_len >= sizeof(*wh))
+		return (ieee80211_find_rxnode(ic, wh));
+
+	return (NULL);
+}
+
 static void
 urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct urtwn_softc *sc = usbd_xfer_softc(xfer);
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_frame_min *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *m = NULL, *next;
 	struct urtwn_data *data;
-	int8_t nf;
-	int rssi = 1;
+	int8_t nf, rssi;
 
 	URTWN_ASSERT_LOCKED(sc);
 
@@ -950,7 +978,7 @@ urtwn_bulk_rx_callback(struct usb_xfer *
 		if (data == NULL)
 			goto tr_setup;
 		STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
-		m = urtwn_report_intr(xfer, data, &rssi, &nf);
+		m = urtwn_report_intr(xfer, data);
 		STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
@@ -971,15 +999,13 @@ tr_setup:
 		 * ieee80211_input() because here is at the end of a USB
 		 * callback and safe to unlock.
 		 */
-		URTWN_UNLOCK(sc);
 		while (m != NULL) {
 			next = m->m_next;
 			m->m_next = NULL;
-			wh = mtod(m, struct ieee80211_frame_min *);
-			if (m->m_len >= sizeof(*wh))
-				ni = ieee80211_find_rxnode(ic, wh);
-			else
-				ni = NULL;
+
+			ni = urtwn_rx_frame(sc, m, &rssi);
+			URTWN_UNLOCK(sc);
+
 			nf = URTWN_NOISE_FLOOR;
 			if (ni != NULL) {
 				(void)ieee80211_input(ni, m, rssi - nf, nf);
@@ -988,9 +1014,10 @@ tr_setup:
 				(void)ieee80211_input_all(ic, m, rssi - nf,
 				    nf);
 			}
+
+			URTWN_LOCK(sc);
 			m = next;
 		}
-		URTWN_LOCK(sc);
 		break;
 	default:
 		/* needs it to the inactive queue due to a error. */


More information about the svn-src-head mailing list