On Fri, Apr 24, 2020 at 03:31:12PM +0200, Stefan Sperling wrote:
> On Wed, Apr 22, 2020 at 07:37:10PM +0200, Stefan Sperling wrote:
> > This makes athn(4) offload CCMP encryption and decryption to hardware.
> > CCMP is used with WPA2, so this reduces CPU load on WPA2 networks only.
> >
> > The WPA1 (TKIP) and WEP ciphers remain in software because this simplifies
> > the driver. TKIP in particular is a annoying to deal with on this hardware.
> > Old ciphers should not be used anymore anyway and they don't work in 11n
> > mode.
> >
> > I have successfully tested the following on this device:
> > athn0 at pci1 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 2 int 16
> > athn0: AR9280 rev 2 (2T2R), ROM rev 22, address xx:xx:xx:xx:xx:xx
> >
> > Hostap mode with multiple clients in parallel: wpa2, wpa1, wep, plaintext
> > Client mode: wpa2, plaintext
> >
> > Could anyone else test this?
>
> This patch panics on athn(4) USB devices (reported to me by several people).
> I am working on a fix for USB.
New diff which also works on USB devices (tested on AR9271 and AR9280+AR7010).
diff c50b0f0215d7dd5773e0ee8623d8aa2c7d2107c6
b593e0ca32b1c816510ec76bdd498bc9101dea15
blob - 9dd0499c9704c87fbe039b65f02e907284fea120
blob + 0f78d27c9e99239d6ec08410dd42e65c5781245d
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -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
}
#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_l
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_l
* 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_l
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_l
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, struc
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, struc
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.
blob - a45fe825940b6bb6810a7de7830ccd87d6bcb6fc
blob + eed13c59a4d1991bfa8a2827f3d190b6ae5e6a42
--- sys/dev/ic/ar5008reg.h
+++ sys/dev/ic/ar5008reg.h
@@ -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
blob - b3532eb8263f678c80a44257fe4f55820458a18c
blob + f4c865e299f3302dd9a98aefb15bbfff76296bc0
--- sys/dev/ic/athn.c
+++ sys/dev/ic/athn.c
@@ -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
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,19 +1046,46 @@ athn_set_key(struct ieee80211com *ic, struct ieee80211
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 ieee80
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:
+ if (k->k_cipher == IEEE80211_CIPHER_CCMP) {
entry = (uintptr_t)k->k_priv;
athn_reset_key(sc, entry);
- break;
- case IEEE80211_CIPHER_TKIP:
- 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
blob - 7cd0644df368944fcb0d5a1ecb3a75f3f5d16841
blob + a3549193408fbebd9e2bd5314e2ef8389249583b
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -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 *
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 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 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 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, str
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, str
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 {
blob - c70004ed99d4fa005b265bad80456a7f4b464363
blob + 0c2865315410d92096330b46435b166fc70d4932
--- sys/dev/usb/if_athn_usb.h
+++ sys/dev/usb/if_athn_usb.h
@@ -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];