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
This commit is contained in:
parent
05ab290102
commit
e77cd6fd9e
@ -182,14 +182,15 @@ static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *,
|
||||
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 *vap)
|
||||
}
|
||||
|
||||
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, uint8_t *buf, int pktlen, int *rssi_p)
|
||||
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, struct urtwn_data *data, int *rssi,
|
||||
|
||||
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, struct urtwn_data *data, int *rssi,
|
||||
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, uint8_t *buf, int len, int *rssi,
|
||||
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 urtwn_softc *sc, void *arg)
|
||||
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 *xfer, usb_error_t error)
|
||||
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 @@ urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
* 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 @@ urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
(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. */
|
||||
|
Loading…
Reference in New Issue
Block a user