Jonathan Matthew(jonat...@d14n.org) on 2020.06.05 21:54:30 +1000: > This enables use of hardware crypto for CCMP in urtwn(4). As with other > drivers, this reduces cpu usage significantly when moving lots of data. > I've tested this on an assortment of hardware (RTL8188CUS, RTL8188EU, > RTL8192EU) with no problems, and this is one of the few things that > remains constant across a lot of Realtek wifi chips, but some wider > testing couldn't hurt. Since this touches the code shared with rtwn(4), > I've also tested that that still works.
Works on urtwn0 at uhub2 port 2 configuration 1 interface 0 "Realtek 802.11n NIC" rev 2.00/0.00 addr 3 urtwn0: MAC/BB RTL8188EU, RF 6052 1T1R, address d4:6e:0e:29:e2:84 usb stick, on armv7. In a quick test, download of a 10MB large file is faster with your diff, up from 1MB/s to now 1.6MB/s. /Benno > > > Index: ic/r92creg.h > =================================================================== > RCS file: /cvs/src/sys/dev/ic/r92creg.h,v > retrieving revision 1.24 > diff -u -p -r1.24 r92creg.h > --- ic/r92creg.h 11 Mar 2019 06:19:33 -0000 1.24 > +++ ic/r92creg.h 5 Jun 2020 11:52:21 -0000 > @@ -688,6 +688,16 @@ > #define R92C_CAMCMD_CLR 0x40000000 > #define R92C_CAMCMD_POLLING 0x80000000 > > +/* Bits for R92C_SECCFG. */ > +#define R92C_SECCFG_TXUCKEY_DEF 0x0001 > +#define R92C_SECCFG_RXUCKEY_DEF 0x0002 > +#define R92C_SECCFG_TXENC_ENA 0x0004 > +#define R92C_SECCFG_RXENC_ENA 0x0008 > +#define R92C_SECCFG_CMP_A2 0x0010 > +#define R92C_SECCFG_MC_SRCH_DIS 0x0020 > +#define R92C_SECCFG_TXBCKEY_DEF 0x0040 > +#define R92C_SECCFG_RXBCKEY_DEF 0x0080 > + > /* IMR */ > > /*Beacon DMA interrupt 6 */ > Index: ic/rtwn.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/rtwn.c,v > retrieving revision 1.49 > diff -u -p -r1.49 rtwn.c > --- ic/rtwn.c 9 Jan 2020 14:35:19 -0000 1.49 > +++ ic/rtwn.c 5 Jun 2020 11:52:22 -0000 > @@ -3154,6 +3154,14 @@ rtwn_init(struct ifnet *ifp) > /* Clear per-station keys table. */ > rtwn_cam_init(sc); > > + /* Enable decryption / encryption. */ > + if (sc->chip & RTWN_CHIP_USB) { > + rtwn_write_2(sc, R92C_SECCFG, > + R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | > + R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXENC_ENA | > + R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF); > + } > + > /* Enable hardware sequence numbering. */ > rtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff); > > @@ -3204,14 +3212,14 @@ rtwn_init(struct ifnet *ifp) > ifq_clr_oactive(&ifp->if_snd); > ifp->if_flags |= IFF_RUNNING; > > -#ifdef notyet > - if (ic->ic_flags & IEEE80211_F_WEPON) { > + if ((ic->ic_flags & IEEE80211_F_WEPON) && > + (sc->chip & RTWN_CHIP_USB)) { > /* Install WEP keys. */ > for (i = 0; i < IEEE80211_WEP_NKID; i++) > ic->ic_set_key(ic, NULL, &ic->ic_nw_keys[i]); > sc->sc_ops.wait_async(sc->sc_ops.cookie); > } > -#endif > + > if (ic->ic_opmode == IEEE80211_M_MONITOR) > ieee80211_new_state(ic, IEEE80211_S_RUN, -1); > else > Index: usb/if_urtwn.c > =================================================================== > RCS file: /cvs/src/sys/dev/usb/if_urtwn.c,v > retrieving revision 1.89 > diff -u -p -r1.89 if_urtwn.c > --- usb/if_urtwn.c 26 May 2020 06:04:30 -0000 1.89 > +++ usb/if_urtwn.c 5 Jun 2020 11:52:22 -0000 > @@ -490,10 +490,8 @@ urtwn_attach(struct device *parent, stru > > ic->ic_updateslot = urtwn_updateslot; > ic->ic_updateedca = urtwn_updateedca; > -#ifdef notyet > ic->ic_set_key = urtwn_set_key; > ic->ic_delete_key = urtwn_delete_key; > -#endif > /* Override state transition machine. */ > ic->ic_newstate = urtwn_newstate; > > @@ -1035,6 +1033,10 @@ urtwn_set_key(struct ieee80211com *ic, s > struct urtwn_softc *sc = (struct urtwn_softc *)self; > struct urtwn_cmd_key cmd; > > + /* Only handle keys for CCMP */ > + if (k->k_cipher != IEEE80211_CIPHER_CCMP) > + return ieee80211_set_key(ic, ni, k); > + > /* Defer setting of WEP keys until interface is brought up. */ > if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) != > (IFF_UP | IFF_RUNNING)) > @@ -1065,6 +1067,12 @@ urtwn_delete_key(struct ieee80211com *ic > struct urtwn_softc *sc = (struct urtwn_softc *)self; > struct urtwn_cmd_key cmd; > > + /* Only handle keys for CCMP */ > + if (k->k_cipher != IEEE80211_CIPHER_CCMP) { > + ieee80211_delete_key(ic, ni, k); > + return; > + } > + > if (!(ic->ic_if.if_flags & IFF_RUNNING) || > ic->ic_state != IEEE80211_S_RUN) > return; /* Nothing to do. */ > @@ -1084,6 +1092,52 @@ urtwn_delete_key_cb(struct urtwn_softc * > rtwn_delete_key(ic, cmd->ni, &cmd->key); > } > > +int > +urtwn_ccmp_decap(struct urtwn_softc *sc, struct mbuf *m, > + struct ieee80211_node *ni) > +{ > + struct ieee80211com *ic = &sc->sc_sc.sc_ic; > + struct ieee80211_key *k; > + struct ieee80211_frame *wh; > + uint64_t pn, *prsc; > + uint8_t *ivp; > + uint8_t tid; > + int hdrlen, hasqos; > + > + k = ieee80211_get_rxkey(ic, m, ni); > + if (k == NULL) > + return 1; > + > + wh = mtod(m, struct ieee80211_frame *); > + hdrlen = ieee80211_get_hdrlen(wh); > + ivp = (uint8_t *)wh + hdrlen; > + > + /* Check that ExtIV bit is set. */ > + if (!(ivp[3] & IEEE80211_WEP_EXTIV)) > + return 1; > + > + hasqos = ieee80211_has_qos(wh); > + tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; > + prsc = &k->k_rsc[tid]; > + > + /* Extract the 48-bit PN from the CCMP header. */ > + pn = (uint64_t)ivp[0] | > + (uint64_t)ivp[1] << 8 | > + (uint64_t)ivp[4] << 16 | > + (uint64_t)ivp[5] << 24 | > + (uint64_t)ivp[6] << 32 | > + (uint64_t)ivp[7] << 40; > + if (pn <= *prsc) { > + ic->ic_stats.is_ccmp_replays++; > + return 1; > + } > + /* Last seen packet number is updated in ieee80211_inputm(). */ > + > + /* Strip MIC. IV will be stripped by ieee80211_inputm(). */ > + m_adj(m, -IEEE80211_CCMP_MICLEN); > + return 0; > +} > + > void > urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, > struct mbuf_list *ml) > @@ -1197,6 +1251,21 @@ urtwn_rx_frame(struct urtwn_softc *sc, u > rxi.rxi_flags = 0; > rxi.rxi_rssi = rssi; > rxi.rxi_tstamp = 0; /* Unused. */ > + > + /* Handle hardware decryption. */ > + if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) > + && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && > + (ni->ni_flags & IEEE80211_NODE_RXPROT) && > + ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) { > + if (urtwn_ccmp_decap(sc, m, ni) != 0) { > + ifp->if_ierrors++; > + m_freem(m); > + ieee80211_release_node(ic, ni); > + return; > + } > + rxi.rxi_flags |= IEEE80211_RXI_HWDEC; > + } > + > ieee80211_inputm(ifp, m, ni, &rxi, ml); > /* Node is no longer needed. */ > ieee80211_release_node(ic, ni); > @@ -1360,37 +1429,28 @@ urtwn_tx_fill_desc(struct urtwn_softc *s > struct r92c_tx_desc_usb *txd; > struct ieee80211com *ic = &sc->sc_sc.sc_ic; > uint8_t raid, type; > + uint32_t pktlen; > > txd = (struct r92c_tx_desc_usb *)*txdp; > (*txdp) += sizeof(*txd); > memset(txd, 0, sizeof(*txd)); > > + pktlen = m->m_pkthdr.len; > + if (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) { > + txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, > + R92C_TXDW1_CIPHER_AES)); > + pktlen += IEEE80211_CCMP_HDRLEN; > + } > + > type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; > > txd->txdw0 |= htole32( > - SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | > + SM(R92C_TXDW0_PKTLEN, pktlen) | > SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | > R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); > if (IEEE80211_IS_MULTICAST(wh->i_addr1)) > txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); > > -#ifdef notyet > - if (k != NULL) { > - switch (k->k_cipher) { > - case IEEE80211_CIPHER_WEP40: > - case IEEE80211_CIPHER_WEP104: > - case IEEE80211_CIPHER_TKIP: > - cipher = R92C_TXDW1_CIPHER_RC4; > - break; > - case IEEE80211_CIPHER_CCMP: > - cipher = R92C_TXDW1_CIPHER_AES; > - break; > - default: > - cipher = R92C_TXDW1_CIPHER_NONE; > - } > - txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher)); > - } > -#endif > if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && > type == IEEE80211_FC0_TYPE_DATA) { > if (ic->ic_curmode == IEEE80211_MODE_11B || > @@ -1413,7 +1473,7 @@ urtwn_tx_fill_desc(struct urtwn_softc *s > SM(R92C_TXDW1_RAID, raid) | R92C_TXDW1_AGGBK); > } > > - if (m->m_pkthdr.len + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { > + if (pktlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { > txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | > R92C_TXDW4_HWRTSEN); > } else if (ic->ic_flags & IEEE80211_F_USEPROT) { > @@ -1468,6 +1528,7 @@ urtwn_tx_fill_desc_gen2(struct urtwn_sof > struct r92e_tx_desc_usb *txd; > struct ieee80211com *ic = &sc->sc_sc.sc_ic; > uint8_t raid, type; > + uint32_t pktlen; > > txd = (struct r92e_tx_desc_usb *)*txdp; > (*txdp) += sizeof(*txd); > @@ -1475,17 +1536,20 @@ urtwn_tx_fill_desc_gen2(struct urtwn_sof > > type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; > > + pktlen = m->m_pkthdr.len; > + if (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) { > + txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, > + R92C_TXDW1_CIPHER_AES)); > + pktlen += IEEE80211_CCMP_HDRLEN; > + } > + > txd->txdw0 |= htole32( > - SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | > + SM(R92C_TXDW0_PKTLEN, pktlen) | > SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | > R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); > if (IEEE80211_IS_MULTICAST(wh->i_addr1)) > txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); > > -#ifdef notyet > - /* cipher */ > -#endif > - > if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && > type == IEEE80211_FC0_TYPE_DATA) { > if (ic->ic_curmode == IEEE80211_MODE_11B || > @@ -1500,7 +1564,7 @@ urtwn_tx_fill_desc_gen2(struct urtwn_sof > /* Request TX status report for AMRR */ > txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT | R88E_TXDW2_AGGBK); > > - if (m->m_pkthdr.len + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { > + if (pktlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { > txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | > R92C_TXDW4_HWRTSEN); > } else if (ic->ic_flags & IEEE80211_F_USEPROT) { > @@ -1549,16 +1613,18 @@ urtwn_tx(void *cookie, struct mbuf *m, s > struct usbd_pipe *pipe; > uint16_t qos, sum; > uint8_t tid, qid; > - int i, xferlen, error; > + int i, xferlen, error, headerlen; > uint8_t *txdp; > > wh = mtod(m, struct ieee80211_frame *); > > if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { > k = ieee80211_get_txkey(ic, wh, ni); > - if ((m = ieee80211_encrypt(ic, m, k)) == NULL) > - return (ENOBUFS); > - wh = mtod(m, struct ieee80211_frame *); > + if (k->k_cipher != IEEE80211_CIPHER_CCMP) { > + if ((m = ieee80211_encrypt(ic, m, k)) == NULL) > + return (ENOBUFS); > + wh = mtod(m, struct ieee80211_frame *); > + } > } > > if (ieee80211_has_qos(wh)) { > @@ -1611,9 +1677,31 @@ urtwn_tx(void *cookie, struct mbuf *m, s > } > #endif > > - xferlen = (txdp - data->buf) + m->m_pkthdr.len; > - m_copydata(m, 0, m->m_pkthdr.len, txdp); > - m_freem(m); > + if (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) { > + xferlen = (txdp - data->buf) + m->m_pkthdr.len + > + IEEE80211_CCMP_HDRLEN; > + headerlen = ieee80211_get_hdrlen(wh); > + > + m_copydata(m, 0, headerlen, txdp); > + txdp += headerlen; > + > + k->k_tsc++; > + txdp[0] = k->k_tsc; > + txdp[1] = k->k_tsc >> 8; > + txdp[2] = 0; > + txdp[3] = k->k_id | IEEE80211_WEP_EXTIV; > + txdp[4] = k->k_tsc >> 16; > + txdp[5] = k->k_tsc >> 24; > + txdp[6] = k->k_tsc >> 32; > + txdp[7] = k->k_tsc >> 40; > + txdp += IEEE80211_CCMP_HDRLEN; > + > + m_copydata(m, headerlen, m->m_pkthdr.len - headerlen, txdp); > + } else { > + xferlen = (txdp - data->buf) + m->m_pkthdr.len; > + m_copydata(m, 0, m->m_pkthdr.len, txdp); > + m_freem(m); > + } > > data->pipe = pipe; > usbd_setup_xfer(data->xfer, pipe, data, data->buf, xferlen, >