summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2020-07-06 11:28:52 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2020-07-06 11:28:52 +0000
commitd897590169e46a9bea5b93c087eac15cab156186 (patch)
tree378e022d36d780e298da330a2074c9290119d0da /sys
parent7933f5a19aaa65bfa185cd5f3ced80786f900268 (diff)
Repair athn(4) in client mode against WPA2 access points.
Client mode was subtly broken after support for CCMP offload was added. In client mode we should be using the first key table slot for our CCMP pairwise key, not an arbitrary slot based on our association ID (as is done in hostap mode). When the interface came up again after being reset the CCMP hardware engine was left in a non-working state. Apparently the key table was messed up or contained stale entries. Fix a potential timing issue in the code path which attempts to clear the key table on device power-up. For good measure, also clear the key table before the device is powered down. While here, fix off-by-ones in key table slot range checks. Problems reported by Tim Chase, Kevin Chadwick, Austin Hook, Stefan Kapfhammer. Fix tested by me on AR9280 (PCI) and AR9271 (USB) and Kevin Chadwick on AR9280
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/ar5008.c18
-rw-r--r--sys/dev/ic/athn.c25
2 files changed, 30 insertions, 13 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c
index 3a28d87bc88..70dbaf422bd 100644
--- a/sys/dev/ic/ar5008.c
+++ b/sys/dev/ic/ar5008.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5008.c,v 1.59 2020/05/23 08:42:50 stsp Exp $ */
+/* $OpenBSD: ar5008.c,v 1.60 2020/07/06 11:28:51 stsp Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -811,12 +811,20 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *
/* 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 ||
+ 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;
+ } else {
+#ifndef IEEE80211_STA_ONLY
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ if (entry != IEEE80211_WEP_NKID +
+ IEEE80211_AID(ni->ni_associd))
+ return 1;
+ } else
+#endif
+ if (entry != IEEE80211_WEP_NKID)
+ return 1;
+ }
/* Check that ExtIV bit is set. */
if (!(ivp[3] & IEEE80211_WEP_EXTIV))
diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c
index 40725b02c43..5f84db0b1ea 100644
--- a/sys/dev/ic/athn.c
+++ b/sys/dev/ic/athn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: athn.c,v 1.107 2020/04/29 13:13:29 stsp Exp $ */
+/* $OpenBSD: athn.c,v 1.108 2020/07/06 11:28:51 stsp Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -1037,12 +1037,17 @@ athn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
}
if (!(k->k_flags & IEEE80211_KEY_GROUP)) {
- entry = IEEE80211_WEP_NKID + IEEE80211_AID(ni->ni_associd);
+#ifndef IEEE80211_STA_ONLY
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+ entry = IEEE80211_WEP_NKID + IEEE80211_AID(ni->ni_associd);
+ else
+#endif
+ entry = IEEE80211_WEP_NKID;
if (entry >= sc->kc_entries - IEEE80211_WEP_NKID)
return ENOSPC;
} else {
entry = k->k_id;
- if (entry > IEEE80211_WEP_NKID)
+ if (entry >= IEEE80211_WEP_NKID)
return ENOSPC;
}
k->k_priv = (void *)entry;
@@ -3056,10 +3061,6 @@ athn_init(struct ifnet *ifp)
else
athn_config_pcie(sc);
- /* Reset HW key cache entries. */
- for (i = 0; i < sc->kc_entries; i++)
- athn_reset_key(sc, i);
-
ops->enable_antenna_diversity(sc);
#ifdef ATHN_BT_COEXISTENCE
@@ -3086,6 +3087,10 @@ athn_init(struct ifnet *ifp)
/* Enable Rx. */
athn_rx_start(sc);
+ /* Reset HW key cache entries. */
+ for (i = 0; i < sc->kc_entries; i++)
+ athn_reset_key(sc, i);
+
/* Enable interrupts. */
athn_enable_interrupts(sc);
@@ -3121,7 +3126,7 @@ athn_stop(struct ifnet *ifp, int disable)
{
struct athn_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
- int qid;
+ int qid, i;
ifp->if_timer = sc->sc_tx_timer = 0;
ifp->if_flags &= ~IFF_RUNNING;
@@ -3159,6 +3164,10 @@ athn_stop(struct ifnet *ifp, int disable)
athn_set_rxfilter(sc, 0);
athn_stop_rx_dma(sc);
+ /* Reset HW key cache entries. */
+ for (i = 0; i < sc->kc_entries; i++)
+ athn_reset_key(sc, i);
+
athn_reset(sc, 0);
athn_init_pll(sc, NULL);
athn_set_power_awake(sc);