summaryrefslogtreecommitdiff
path: root/sys/dev/usb/if_urtwn.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/if_urtwn.c')
-rw-r--r--sys/dev/usb/if_urtwn.c158
1 files changed, 123 insertions, 35 deletions
diff --git a/sys/dev/usb/if_urtwn.c b/sys/dev/usb/if_urtwn.c
index e7cc2f4bb2b..c2d12f00339 100644
--- a/sys/dev/usb/if_urtwn.c
+++ b/sys/dev/usb/if_urtwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_urtwn.c,v 1.89 2020/05/26 06:04:30 jsg Exp $ */
+/* $OpenBSD: if_urtwn.c,v 1.90 2020/06/11 00:56:12 jmatthew Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -490,10 +490,8 @@ urtwn_attach(struct device *parent, struct device *self, void *aux)
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, struct ieee80211_node *ni,
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 ieee80211_node *ni,
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 *sc, void *arg)
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, uint8_t *buf, int pktlen,
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 *sc, uint8_t **txdp, struct mbuf *m,
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 *sc, uint8_t **txdp, struct mbuf *m,
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_softc *sc, uint8_t **txdp, struct mbuf *m,
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_softc *sc, uint8_t **txdp, struct mbuf *m,
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_softc *sc, uint8_t **txdp, struct mbuf *m,
/* 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, struct ieee80211_node *ni)
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, struct ieee80211_node *ni)
}
#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,