summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/ar5008.c201
-rw-r--r--sys/dev/ic/ar5008reg.h3
-rw-r--r--sys/dev/ic/athn.c121
-rw-r--r--sys/dev/usb/if_athn_usb.c58
-rw-r--r--sys/dev/usb/if_athn_usb.h7
5 files changed, 293 insertions, 97 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c
index 9dd0499c970..3d1235de376 100644
--- a/sys/dev/ic/ar5008.c
+++ b/sys/dev/ic/ar5008.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5008.c,v 1.55 2020/02/17 14:37:36 claudio Exp $ */
+/* $OpenBSD: ar5008.c,v 1.56 2020/04/27 08:21:34 stsp Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -77,11 +77,14 @@ void ar5008_rx_free(struct athn_softc *);
void ar5008_rx_enable(struct athn_softc *);
void ar5008_rx_radiotap(struct athn_softc *, struct mbuf *,
struct ar_rx_desc *);
+int ar5008_ccmp_decap(struct athn_softc *, struct mbuf *,
+ struct ieee80211_node *);
void ar5008_rx_intr(struct athn_softc *);
int ar5008_tx_process(struct athn_softc *, int);
void ar5008_tx_intr(struct athn_softc *);
int ar5008_swba_intr(struct athn_softc *);
int ar5008_intr(struct athn_softc *);
+int ar5008_ccmp_encap(struct mbuf *, u_int, struct ieee80211_key *);
int ar5008_tx(struct athn_softc *, struct mbuf *, struct ieee80211_node *,
int);
void ar5008_set_rf_mode(struct athn_softc *, struct ieee80211_channel *);
@@ -254,6 +257,8 @@ ar5008_attach(struct athn_softc *sc)
kc_entries_log = MS(base->deviceCap, AR_EEP_DEVCAP_KC_ENTRIES);
sc->kc_entries = (kc_entries_log != 0) ?
1 << kc_entries_log : AR_KEYTABLE_SIZE;
+ if (sc->kc_entries > AR_KEYTABLE_SIZE)
+ sc->kc_entries = AR_KEYTABLE_SIZE;
sc->txchainmask = base->txMask;
if (sc->mac_ver == AR_SREV_VERSION_5416_PCI &&
@@ -781,6 +786,111 @@ ar5008_rx_radiotap(struct athn_softc *sc, struct mbuf *m,
}
#endif
+int
+ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_key *k;
+ struct ieee80211_frame *wh;
+ struct ieee80211_rx_ba *ba;
+ uint64_t pn, *prsc;
+ u_int8_t *ivp, *mmie;
+ uint8_t tid;
+ uint16_t kid;
+ int hdrlen, hasqos;
+ uintptr_t entry;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+ ivp = mtod(m, u_int8_t *) + hdrlen;
+
+ /* find key for decryption */
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ k = &ni->ni_pairwise_key;
+ } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
+ IEEE80211_FC0_TYPE_MGT) {
+ /* retrieve group data key id from IV field */
+ /* check that IV field is present */
+ if (m->m_len < hdrlen + 4)
+ return 1;
+ kid = ivp[3] >> 6;
+ k = &ic->ic_nw_keys[kid];
+ } else {
+ /* retrieve integrity group key id from MMIE */
+ if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
+ return 1;
+ }
+ /* it is assumed management frames are contiguous */
+ mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
+ /* check that MMIE is valid */
+ if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
+ return 1;
+ }
+ kid = LE_READ_2(&mmie[2]);
+ if (kid != 4 && kid != 5) {
+ return 1;
+ }
+ k = &ic->ic_nw_keys[kid];
+ }
+
+ if (k->k_cipher != IEEE80211_CIPHER_CCMP)
+ return 1;
+
+ /* Sanity checks to ensure this is really a key we installed. */
+ entry = (uintptr_t)k->k_priv;
+ if (k->k_flags & IEEE80211_KEY_GROUP) {
+ if (k->k_id > IEEE80211_WEP_NKID ||
+ entry != k->k_id)
+ return 1;
+ } else if (entry != IEEE80211_WEP_NKID +
+ IEEE80211_AID(ni->ni_associd))
+ return 1;
+
+ /* Check that ExtIV bit is be set. */
+ if (!(ivp[3] & IEEE80211_WEP_EXTIV))
+ return 1;
+
+ hasqos = ieee80211_has_qos(wh);
+ tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+ ba = hasqos ? &ni->ni_rx_ba[tid] : NULL;
+ prsc = &k->k_rsc[0];
+
+ /* 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) {
+ if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) {
+ /*
+ * This is an A-MPDU subframe.
+ * Such frames may be received out of order due to
+ * legitimate retransmissions of failed subframes
+ * in previous A-MPDUs. Duplicates will be handled
+ * in ieee80211_inputm() as part of A-MPDU reordering.
+ *
+ * XXX TODO We can probably do better than this! Store
+ * re-ordered PN in BA agreement state and check it?
+ */
+ } else {
+ ic->ic_stats.is_ccmp_replays++;
+ return 1;
+ }
+ }
+ /* Update last seen packet number. */
+ *prsc = pn;
+
+ /* Clear Protected bit and strip IV. */
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+ memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen);
+ m_adj(m, IEEE80211_CCMP_HDRLEN);
+ /* Strip MIC. */
+ m_adj(m, -IEEE80211_CCMP_MICLEN);
+ return 0;
+}
+
static __inline int
ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
{
@@ -837,9 +947,12 @@ ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
else if (ds->ds_status8 & AR_RXS8_PHY_ERR)
DPRINTFN(6, ("PHY error=0x%x\n",
MS(ds->ds_status8, AR_RXS8_PHY_ERR_CODE)));
- else if (ds->ds_status8 & AR_RXS8_DECRYPT_CRC_ERR)
+ else if ((ds->ds_status8 & AR_RXS8_DECRYPT_CRC_ERR) ||
+ (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ (ds->ds_status8 & AR_RXS8_KEY_MISS))) {
DPRINTFN(6, ("Decryption CRC error\n"));
- else if (ds->ds_status8 & AR_RXS8_MICHAEL_ERR) {
+ ic->ic_stats.is_ccmp_dec_errs++;
+ } else if (ds->ds_status8 & AR_RXS8_MICHAEL_ERR) {
DPRINTFN(2, ("Michael MIC failure\n"));
/* Report Michael MIC failures to net80211. */
ic->ic_stats.is_rx_locmicfail++;
@@ -848,7 +961,8 @@ ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
* XXX Check that it is not a control frame
* (invalid MIC failures on valid ctl frames).
*/
- }
+ } else if (ds->ds_status8 & AR_RXS8_DECRYPT_BUSY_ERR)
+ ic->ic_stats.is_ccmp_dec_errs++;
ifp->if_ierrors++;
goto skip;
}
@@ -911,6 +1025,7 @@ ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
memmove((caddr_t)wh + 2, wh, hdrlen);
m_adj(m, 2);
}
+ wh = mtod(m, struct ieee80211_frame *);
}
#if NBPFILTER > 0
if (__predict_false(sc->sc_drvbpf != NULL))
@@ -924,6 +1039,21 @@ ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
rxi.rxi_rssi = MS(ds->ds_status4, AR_RXS4_RSSI_COMBINED);
rxi.rxi_rssi += AR_DEFAULT_NOISE_FLOOR;
rxi.rxi_tstamp = ds->ds_status2;
+ if (!(wh->i_fc[0] & IEEE80211_FC0_TYPE_CTL) &&
+ (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+ (ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
+ (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+ (IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP))) {
+ if (ar5008_ccmp_decap(sc, m, ni) != 0) {
+ ifp->if_ierrors++;
+ ieee80211_release_node(ic, ni);
+ m_freem(m);
+ goto skip;
+ }
+ rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
+ }
ieee80211_inputm(ifp, m, ni, &rxi, ml);
/* Node is no longer needed. */
@@ -1288,6 +1418,33 @@ ar5008_intr(struct athn_softc *sc)
}
int
+ar5008_ccmp_encap(struct mbuf *m, u_int hdrlen, struct ieee80211_key *k)
+{
+ struct mbuf *n;
+ uint8_t *ivp;
+ int off;
+
+ /* Insert IV for CCMP hardware encryption. */
+ n = m_makespace(m, hdrlen, IEEE80211_CCMP_HDRLEN, &off);
+ if (n == NULL) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ ivp = mtod(n, uint8_t *) + off;
+ k->k_tsc++;
+ ivp[0] = k->k_tsc;
+ ivp[1] = k->k_tsc >> 8;
+ ivp[2] = 0;
+ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV;
+ ivp[4] = k->k_tsc >> 16;
+ ivp[5] = k->k_tsc >> 24;
+ ivp[6] = k->k_tsc >> 32;
+ ivp[7] = k->k_tsc >> 40;
+
+ return 0;
+}
+
+int
ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
int txflags)
{
@@ -1330,8 +1487,15 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
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);
+ if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
+ u_int hdrlen = ieee80211_get_hdrlen(wh);
+ if (ar5008_ccmp_encap(m, hdrlen, k) != 0)
+ return (ENOBUFS);
+ } else {
+ if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
+ return (ENOBUFS);
+ k = NULL; /* skip hardware crypto further below */
+ }
wh = mtod(m, struct ieee80211_frame *);
}
@@ -1461,28 +1625,13 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
IEEE80211_QOS_ACK_POLICY_NOACK))
ds->ds_ctl1 |= AR_TXC1_NO_ACK;
- if (0 && k != NULL) {
- /*
- * Map 802.11 cipher to hardware encryption type and
- * compute MIC+ICV overhead.
- */
- switch (k->k_cipher) {
- case IEEE80211_CIPHER_WEP40:
- case IEEE80211_CIPHER_WEP104:
- encrtype = AR_ENCR_TYPE_WEP;
- totlen += 4;
- break;
- case IEEE80211_CIPHER_TKIP:
- encrtype = AR_ENCR_TYPE_TKIP;
- totlen += 12;
- break;
- case IEEE80211_CIPHER_CCMP:
+ if (k != NULL) {
+ /* Map 802.11 cipher to hardware encryption type. */
+ if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
encrtype = AR_ENCR_TYPE_AES;
- totlen += 8;
- break;
- default:
+ totlen += IEEE80211_CCMP_MICLEN;
+ } else
panic("unsupported cipher");
- }
/*
* NB: The key cache entry index is stored in the key
* private field when the key is installed.
diff --git a/sys/dev/ic/ar5008reg.h b/sys/dev/ic/ar5008reg.h
index a45fe825940..817e90df478 100644
--- a/sys/dev/ic/ar5008reg.h
+++ b/sys/dev/ic/ar5008reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5008reg.h,v 1.6 2019/07/24 07:53:57 stsp Exp $ */
+/* $OpenBSD: ar5008reg.h,v 1.7 2020/04/27 08:21:34 stsp Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -927,6 +927,7 @@ struct ar_rx_desc {
#define AR_RXS8_KEY_IDX_S 9
#define AR_RXS8_POST_DELIM_CRC_ERR 0x00040000
#define AR_RXS8_DECRYPT_BUSY_ERR 0x40000000
+#define AR_RXS8_KEY_MISS 0x80000000
#define AR_MAX_PWR_RANGE_IN_HALF_DB 64
#define AR9285_PD_GAIN_BOUNDARY_DEFAULT 58
diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c
index 88784561c13..81539232169 100644
--- a/sys/dev/ic/athn.c
+++ b/sys/dev/ic/athn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: athn.c,v 1.104 2019/05/17 01:05:20 kevlo Exp $ */
+/* $OpenBSD: athn.c,v 1.105 2020/04/27 08:21:34 stsp Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -244,9 +244,10 @@ athn_attach(struct athn_softc *sc)
/*
* In HostAP mode, the number of STAs that we can handle is
* limited by the number of entries in the HW key cache.
- * TKIP keys consume 2 entries in the cache.
+ * TKIP keys would consume 2 entries in this cache but we
+ * only use the hardware crypto engine for CCMP.
*/
- ic->ic_max_nnodes = (sc->kc_entries / 2) - IEEE80211_WEP_NKID;
+ ic->ic_max_nnodes = sc->kc_entries - IEEE80211_WEP_NKID;
if (ic->ic_max_nnodes > IEEE80211_CACHE_SIZE)
ic->ic_max_nnodes = IEEE80211_CACHE_SIZE;
@@ -373,10 +374,8 @@ athn_attach(struct athn_softc *sc)
ic->ic_newassoc = athn_newassoc;
ic->ic_updateslot = athn_updateslot;
ic->ic_updateedca = athn_updateedca;
-#ifdef notyet
ic->ic_set_key = athn_set_key;
ic->ic_delete_key = athn_delete_key;
-#endif
/* Override 802.11 state transition machine. */
sc->sc_newstate = ic->ic_newstate;
@@ -990,6 +989,12 @@ athn_reset_key(struct athn_softc *sc, int entry)
* NB: Key cache registers access special memory area that requires
* two 32-bit writes to actually update the values in the internal
* memory. Consequently, writes must be grouped by pair.
+ *
+ * All writes to registers with an offset of 0x0 or 0x8 write to a
+ * temporary register. A write to a register with an offset of 0x4
+ * or 0xc writes concatenates the written value with the value in
+ * the temporary register and writes the result to key cache memory.
+ * The actual written memory area is 50 bits wide.
*/
AR_WRITE(sc, AR_KEYTABLE_KEY0(entry), 0);
AR_WRITE(sc, AR_KEYTABLE_KEY1(entry), 0);
@@ -1011,58 +1016,29 @@ athn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
struct ieee80211_key *k)
{
struct athn_softc *sc = ic->ic_softc;
- const uint8_t *txmic, *rxmic, *key, *addr;
- uintptr_t entry, micentry;
- uint32_t type, lo, hi;
+ const uint8_t *key, *addr;
+ uintptr_t entry;
+ uint32_t lo, hi, unicast;
- switch (k->k_cipher) {
- case IEEE80211_CIPHER_WEP40:
- type = AR_KEYTABLE_TYPE_40;
- break;
- case IEEE80211_CIPHER_WEP104:
- type = AR_KEYTABLE_TYPE_104;
- break;
- case IEEE80211_CIPHER_TKIP:
- type = AR_KEYTABLE_TYPE_TKIP;
- break;
- case IEEE80211_CIPHER_CCMP:
- type = AR_KEYTABLE_TYPE_CCM;
- break;
- default:
- /* Fallback to software crypto for other ciphers. */
- return (ieee80211_set_key(ic, ni, k));
+ if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
+ /* Use software crypto for ciphers other than CCMP. */
+ return ieee80211_set_key(ic, ni, k);
}
- if (!(k->k_flags & IEEE80211_KEY_GROUP))
+ if (!(k->k_flags & IEEE80211_KEY_GROUP)) {
entry = IEEE80211_WEP_NKID + IEEE80211_AID(ni->ni_associd);
- else
+ if (entry >= sc->kc_entries - IEEE80211_WEP_NKID)
+ return ENOSPC;
+ } else {
entry = k->k_id;
+ if (entry > IEEE80211_WEP_NKID)
+ return ENOSPC;
+ }
k->k_priv = (void *)entry;
/* NB: See note about key cache registers access above. */
key = k->k_key;
- if (type == AR_KEYTABLE_TYPE_TKIP) {
-#ifndef IEEE80211_STA_ONLY
- if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
- txmic = &key[16];
- rxmic = &key[24];
- } else
-#endif
- {
- rxmic = &key[16];
- txmic = &key[24];
- }
- /* Tx+Rx MIC key is at entry + 64. */
- micentry = entry + 64;
- AR_WRITE(sc, AR_KEYTABLE_KEY0(micentry), LE_READ_4(&rxmic[0]));
- AR_WRITE(sc, AR_KEYTABLE_KEY1(micentry), LE_READ_2(&txmic[2]));
- AR_WRITE(sc, AR_KEYTABLE_KEY2(micentry), LE_READ_4(&rxmic[4]));
- AR_WRITE(sc, AR_KEYTABLE_KEY3(micentry), LE_READ_2(&txmic[0]));
-
- AR_WRITE(sc, AR_KEYTABLE_KEY4(micentry), LE_READ_4(&txmic[4]));
- AR_WRITE(sc, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR);
- }
AR_WRITE(sc, AR_KEYTABLE_KEY0(entry), LE_READ_4(&key[ 0]));
AR_WRITE(sc, AR_KEYTABLE_KEY1(entry), LE_READ_2(&key[ 4]));
@@ -1070,18 +1046,45 @@ athn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
AR_WRITE(sc, AR_KEYTABLE_KEY3(entry), LE_READ_2(&key[10]));
AR_WRITE(sc, AR_KEYTABLE_KEY4(entry), LE_READ_4(&key[12]));
- AR_WRITE(sc, AR_KEYTABLE_TYPE(entry), type);
+ AR_WRITE(sc, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CCM);
+ unicast = AR_KEYTABLE_VALID;
if (!(k->k_flags & IEEE80211_KEY_GROUP)) {
addr = ni->ni_macaddr;
lo = LE_READ_4(&addr[0]);
hi = LE_READ_2(&addr[4]);
lo = lo >> 1 | hi << 31;
hi = hi >> 1;
- } else
- lo = hi = 0;
+ } else {
+#ifndef IEEE80211_STA_ONLY
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ uint8_t groupaddr[ETHER_ADDR_LEN];
+ IEEE80211_ADDR_COPY(groupaddr, ic->ic_myaddr);
+ groupaddr[0] |= 0x01;
+ lo = LE_READ_4(&groupaddr[0]);
+ hi = LE_READ_2(&groupaddr[4]);
+ lo = lo >> 1 | hi << 31;
+ hi = hi >> 1;
+ /*
+ * KEYTABLE_VALID indicates that the address
+ * is a unicast address which must match the
+ * transmitter address when decrypting frames.
+ * Not setting KEYTABLE_VALID allows hardware to
+ * use this key for multicast frame decryption.
+ */
+ unicast = 0;
+ } else
+#endif
+ lo = hi = 0;
+ }
AR_WRITE(sc, AR_KEYTABLE_MAC0(entry), lo);
- AR_WRITE(sc, AR_KEYTABLE_MAC1(entry), hi | AR_KEYTABLE_VALID);
+ AR_WRITE(sc, AR_KEYTABLE_MAC1(entry), hi | unicast);
+
+ AR_WRITE_BARRIER(sc);
+
+ /* Enable HW crypto. */
+ AR_CLRBITS(sc, AR_DIAG_SW, AR_DIAG_ENCRYPT_DIS | AR_DIAG_DECRYPT_DIS);
+
AR_WRITE_BARRIER(sc);
return (0);
}
@@ -1093,22 +1096,12 @@ athn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
struct athn_softc *sc = ic->ic_softc;
uintptr_t entry;
- switch (k->k_cipher) {
- case IEEE80211_CIPHER_WEP40:
- case IEEE80211_CIPHER_WEP104:
- case IEEE80211_CIPHER_CCMP:
- entry = (uintptr_t)k->k_priv;
- athn_reset_key(sc, entry);
- break;
- case IEEE80211_CIPHER_TKIP:
+ if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
entry = (uintptr_t)k->k_priv;
athn_reset_key(sc, entry);
- athn_reset_key(sc, entry + 64);
- break;
- default:
- /* Fallback to software crypto for other ciphers. */
+ explicit_bzero(k, sizeof(*k));
+ } else
ieee80211_delete_key(ic, ni, k);
- }
}
void
diff --git a/sys/dev/usb/if_athn_usb.c b/sys/dev/usb/if_athn_usb.c
index 7cd0644df36..abdefe08dd0 100644
--- a/sys/dev/usb/if_athn_usb.c
+++ b/sys/dev/usb/if_athn_usb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_athn_usb.c,v 1.55 2019/11/25 11:32:17 mpi Exp $ */
+/* $OpenBSD: if_athn_usb.c,v 1.56 2020/04/27 08:21:35 stsp Exp $ */
/*-
* Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr>
@@ -53,6 +53,7 @@
#include <net80211/ieee80211_radiotap.h>
#include <dev/ic/athnreg.h>
+#include <dev/ic/ar5008reg.h>
#include <dev/ic/athnvar.h>
#include <dev/usb/usb.h>
@@ -190,6 +191,9 @@ int athn_usb_ioctl(struct ifnet *, u_long, caddr_t);
int athn_usb_init(struct ifnet *);
void athn_usb_stop(struct ifnet *);
void ar9271_load_ani(struct athn_softc *);
+int ar5008_ccmp_decap(struct athn_softc *, struct mbuf *,
+ struct ieee80211_node *);
+int ar5008_ccmp_encap(struct mbuf *, u_int, struct ieee80211_key *);
/* Shortcut. */
#define athn_usb_wmi_cmd(sc, cmd_id) \
@@ -341,9 +345,9 @@ athn_usb_attachhook(struct device *self)
#endif
ic->ic_updateslot = athn_usb_updateslot;
ic->ic_updateedca = athn_usb_updateedca;
-#ifdef notyet
ic->ic_set_key = athn_usb_set_key;
ic->ic_delete_key = athn_usb_delete_key;
+#ifdef notyet
ic->ic_ampdu_tx_start = athn_usb_ampdu_tx_start;
ic->ic_ampdu_tx_stop = athn_usb_ampdu_tx_stop;
#endif
@@ -1653,6 +1657,7 @@ athn_usb_set_key_cb(struct athn_usb_softc *usc, void *arg)
int s;
s = splnet();
+ athn_usb_write_barrier(&usc->sc_sc);
athn_set_key(ic, cmd->ni, cmd->key);
if (cmd->ni != NULL)
ieee80211_release_node(ic, cmd->ni);
@@ -2040,6 +2045,12 @@ athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m,
if (__predict_false(datalen < sizeof(*wh) + IEEE80211_CRC_LEN))
goto skip;
+ if (rs->rs_status != 0) {
+ if (rs->rs_status & AR_RXS_RXERR_DECRYPT)
+ ic->ic_stats.is_ccmp_dec_errs++;
+ ifp->if_ierrors++;
+ goto skip;
+ }
m_adj(m, sizeof(*rs)); /* Strip Rx status. */
s = splnet();
@@ -2055,6 +2066,7 @@ athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m,
memmove((caddr_t)wh + 2, wh, hdrlen);
m_adj(m, 2);
}
+ wh = mtod(m, struct ieee80211_frame *);
}
#if NBPFILTER > 0
if (__predict_false(sc->sc_drvbpf != NULL))
@@ -2067,6 +2079,21 @@ athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m,
rxi.rxi_flags = 0;
rxi.rxi_rssi = rs->rs_rssi + AR_USB_DEFAULT_NF;
rxi.rxi_tstamp = betoh64(rs->rs_tstamp);
+ if (!(wh->i_fc[0] & IEEE80211_FC0_TYPE_CTL) &&
+ (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+ (ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
+ (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+ (IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP))) {
+ if (ar5008_ccmp_decap(sc, m, ni) != 0) {
+ ifp->if_ierrors++;
+ ieee80211_release_node(ic, ni);
+ splx(s);
+ goto skip;
+ }
+ rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
+ }
ieee80211_inputm(ifp, m, ni, &rxi, ml);
/* Node is no longer needed. */
@@ -2247,8 +2274,15 @@ athn_usb_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
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);
+ if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
+ u_int hdrlen = ieee80211_get_hdrlen(wh);
+ if (ar5008_ccmp_encap(m, hdrlen, k) != 0)
+ return (ENOBUFS);
+ } else {
+ if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
+ return (ENOBUFS);
+ k = NULL; /* skip hardware crypto further below */
+ }
wh = mtod(m, struct ieee80211_frame *);
}
if ((hasqos = ieee80211_has_qos(wh))) {
@@ -2305,7 +2339,21 @@ athn_usb_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
txf->flags |= htobe32(AR_HTC_TX_RTSCTS);
}
- txf->key_idx = 0xff;
+
+ if (k != NULL) {
+ /* Map 802.11 cipher to hardware encryption type. */
+ if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
+ txf->key_type = AR_ENCR_TYPE_AES;
+ } else
+ panic("unsupported cipher");
+ /*
+ * NB: The key cache entry index is stored in the key
+ * private field when the key is installed.
+ */
+ txf->key_idx = (uintptr_t)k->k_priv;
+ } else
+ txf->key_idx = 0xff;
+
txf->cookie = an->sta_index;
frm = (uint8_t *)&txf[1];
} else {
diff --git a/sys/dev/usb/if_athn_usb.h b/sys/dev/usb/if_athn_usb.h
index c70004ed99d..0f5525eff24 100644
--- a/sys/dev/usb/if_athn_usb.h
+++ b/sys/dev/usb/if_athn_usb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_athn_usb.h,v 1.10 2018/02/05 09:52:03 stsp Exp $ */
+/* $OpenBSD: if_athn_usb.h,v 1.11 2020/04/27 08:21:35 stsp Exp $ */
/*-
* Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr>
@@ -338,6 +338,11 @@ struct ar_rx_status {
uint64_t rs_tstamp;
uint16_t rs_datalen;
uint8_t rs_status;
+#define AR_RXS_RXERR_CRC 0x01
+#define AR_RXS_RXERR_PHY 0x02
+#define AR_RXS_RXERR_FIFO 0x04
+#define AR_RXS_RXERR_DECRYPT 0x08
+#define AR_RXS_RXERR_MIC 0x10
uint8_t rs_phyerr;
int8_t rs_rssi;
int8_t rs_rssi_ctl[AR_MAX_CHAINS];