From d897590169e46a9bea5b93c087eac15cab156186 Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Mon, 6 Jul 2020 11:28:52 +0000 Subject: 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 --- sys/dev/ic/ar5008.c | 18 +++++++++++++----- sys/dev/ic/athn.c | 25 +++++++++++++++++-------- 2 files changed, 30 insertions(+), 13 deletions(-) (limited to 'sys') 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 @@ -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 @@ -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); -- cgit v1.2.3