From owner-svn-src-head@freebsd.org Mon Dec 14 13:05:17 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id BBF63A43DF8; Mon, 14 Dec 2015 13:05:17 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 7CF0C1822; Mon, 14 Dec 2015 13:05:17 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBED5GXJ088462; Mon, 14 Dec 2015 13:05:16 GMT (envelope-from avos@FreeBSD.org) Received: (from avos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBED5Ggg088461; Mon, 14 Dec 2015 13:05:16 GMT (envelope-from avos@FreeBSD.org) Message-Id: <201512141305.tBED5Ggg088461@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avos set sender to avos@FreeBSD.org using -f From: Andriy Voskoboinyk Date: Mon, 14 Dec 2015 13:05:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r292207 - head/sys/dev/usb/wlan X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Dec 2015 13:05:17 -0000 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. */