svn commit: r309481 - head/sys/dev/usb/wlan
Andriy Voskoboinyk
avos at FreeBSD.org
Sat Dec 3 16:02:54 UTC 2016
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. */
More information about the svn-src-all
mailing list