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