Index: head/sys/dev/usb/wlan/if_urtwn.c =================================================================== --- head/sys/dev/usb/wlan/if_urtwn.c +++ head/sys/dev/usb/wlan/if_urtwn.c @@ -182,14 +182,15 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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_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 @@ 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 @@ * 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 @@ (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. */