diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -1,7 +1,10 @@ /*- - * Copyright (c) 2020-2023 The FreeBSD Foundation + * Copyright (c) 2020-2024 The FreeBSD Foundation * Copyright (c) 2020-2021 Bjoern A. Zeeb * + * Portions of this software were developed by Cheng Cui + * under sponsorship from the FreeBSD Foundation. + * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. * @@ -61,6 +64,7 @@ #define D80211_TRACEX (D80211_TRACE_TX|D80211_TRACE_RX) #define D80211_TRACEX_DUMP (D80211_TRACE_TX_DUMP|D80211_TRACE_RX_DUMP) #define D80211_TRACE_STA 0x00010000 +#define D80211_TRACE_CRYPTO 0x00020000 #define D80211_TRACE_MO 0x00100000 #define D80211_TRACE_MODE 0x0f000000 #define D80211_TRACE_MODE_HT 0x01000000 @@ -144,7 +148,7 @@ struct mbufq txq; struct mtx txq_mtx; - struct ieee80211_key_conf *kc; + struct ieee80211_key_conf *kc[IEEE80211_WEP_NKID]; enum ieee80211_sta_state state; bool txq_ready; /* Can we run the taskq? */ bool added_to_drv; /* Driver knows; i.e. we called ...(). */ diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -1,6 +1,9 @@ /*- - * Copyright (c) 2020-2023 The FreeBSD Foundation - * Copyright (c) 2020-2022 Bjoern A. Zeeb + * Copyright (c) 2020-2024 The FreeBSD Foundation + * Copyright (c) 2020-2024 Bjoern A. Zeeb + * + * Portions of this software were developed by Cheng Cui + * under sponsorship from the FreeBSD Foundation. * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -102,9 +105,15 @@ printf("XXX-TODO %s:%d: UNIMPLEMENTED\n", __func__, __LINE__) #define TRACEOK() if (linuxkpi_debug_80211 & D80211_TRACEOK) \ printf("XXX-TODO %s:%d: TRACEPOINT\n", __func__, __LINE__) + +#define LKPI_80211_TRACE_CRYPTO(fmt, ...) \ + if (linuxkpi_debug_80211 & D80211_TRACE_CRYPTO) \ + printf("LKPI_80211_TRACE_CRYPTO %s:%d: " fmt "\n", \ + __func__, __LINE__, __VA_ARGS__) #else #define UNIMPLEMENTED do { } while (0) #define TRACEOK() do { } while (0) +#define LKPI_80211_TRACE_CRYPTO(...) do { } while(0) #endif /* #define PREP_TX_INFO_DURATION (IEEE80211_TRANS_WAIT * 1000) */ @@ -544,12 +553,20 @@ switch (wlan_cipher_suite) { case WLAN_CIPHER_SUITE_WEP40: + LKPI_80211_TRACE_CRYPTO("supported WLAN Cipher Suite %#08x | %u", + wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff); return (IEEE80211_CRYPTO_WEP); case WLAN_CIPHER_SUITE_TKIP: + LKPI_80211_TRACE_CRYPTO("supported WLAN Cipher Suite %#08x | %u", + wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff); return (IEEE80211_CRYPTO_TKIP); case WLAN_CIPHER_SUITE_CCMP: + LKPI_80211_TRACE_CRYPTO("supported WLAN Cipher Suite %#08x | %u", + wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff); return (IEEE80211_CRYPTO_AES_CCM); case WLAN_CIPHER_SUITE_WEP104: + LKPI_80211_TRACE_CRYPTO("supported WLAN Cipher Suite %#08x | %u", + wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff); return (IEEE80211_CRYPTO_WEP); case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_GCMP: @@ -575,10 +592,13 @@ switch (cipher) { case IEEE80211_CIPHER_TKIP: + LKPI_80211_TRACE_CRYPTO("supported Cipher %#x", cipher); return (WLAN_CIPHER_SUITE_TKIP); case IEEE80211_CIPHER_AES_CCM: + LKPI_80211_TRACE_CRYPTO("supported Cipher %#x", cipher); return (WLAN_CIPHER_SUITE_CCMP); case IEEE80211_CIPHER_WEP: + LKPI_80211_TRACE_CRYPTO("supported Cipher %#x", cipher); if (keylen < 8) return (WLAN_CIPHER_SUITE_WEP40); else @@ -708,20 +728,80 @@ #ifdef LKPI_80211_HW_CRYPTO static int -_lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k, - enum set_key_cmd cmd) +_lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) { struct ieee80211com *ic; struct lkpi_hw *lhw; struct ieee80211_hw *hw; struct lkpi_vif *lvif; + struct lkpi_sta *lsta; struct ieee80211_vif *vif; struct ieee80211_sta *sta; struct ieee80211_node *ni; - struct ieee80211_key_conf *kc; + struct ieee80211_key_conf *kcf; int error; - /* XXX TODO Check (k->wk_flags & IEEE80211_KEY_SWENCRYPT) and don't upload to driver/hw? */ + ic = vap->iv_ic; + lhw = ic->ic_softc; + hw = LHW_TO_HW(lhw); + lvif = VAP_TO_LVIF(vap); + vif = LVIF_TO_VIF(lvif); + + ni = ieee80211_ref_node(vap->iv_bss); + sta = ieee80211_find_sta(vif, ni->ni_bssid); + if (sta == NULL) { + LKPI_80211_TRACE_CRYPTO("sta %6D not found", ni->ni_bssid, ":"); + return (0); + } + lsta = STA_TO_LSTA(sta); + + if (lsta->kc[k->wk_keyix] == NULL) { + LKPI_80211_TRACE_CRYPTO("sta %6D and no key information on " + "keyidx %u, returning success", ni->ni_bssid, ":", + k->wk_keyix); + return (1); + } + kcf = lsta->kc[k->wk_keyix]; + + error = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, sta, kcf); + if (error != 0) { + ic_printf(ic, "%s: set_key cmd %d(%s) for sta %6D failed: %d\n", + __func__, DISABLE_KEY, "DISABLE", ni->ni_bssid, ":", error); + return (0); + } + + LKPI_80211_TRACE_CRYPTO("set_key cmd %d(%s) for sta %6D succeeded: " + "keyidx %u hw_key_idx %u flags %#x", DISABLE_KEY, "DISABLE", + ni->ni_bssid, ":", kcf->keyidx, kcf->hw_key_idx, kcf->flags); + + free(lsta->kc[k->wk_keyix], M_LKPI80211); + lsta->kc[k->wk_keyix] = NULL; + kcf = NULL; + return (1); +} + +static int +lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + + /* XXX-BZ one day we should replace this iterating over VIFs, or node list? */ + return (_lkpi_iv_key_delete(vap, k)); +} + +static int +_lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + struct ieee80211com *ic; + struct lkpi_hw *lhw; + struct ieee80211_hw *hw; + struct lkpi_vif *lvif; + struct lkpi_sta *lsta; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + struct ieee80211_node *ni; + struct ieee80211_key_conf *kcf; + uint32_t lcipher; + int error; ic = vap->iv_ic; lhw = ic->ic_softc; @@ -729,65 +809,83 @@ lvif = VAP_TO_LVIF(vap); vif = LVIF_TO_VIF(lvif); - memset(&kc, 0, sizeof(kc)); - kc = malloc(sizeof(*kc) + k->wk_keylen, M_LKPI80211, M_WAITOK | M_ZERO); - kc->cipher = lkpi_net80211_to_l80211_cipher_suite( - k->wk_cipher->ic_cipher, k->wk_keylen); - kc->keyidx = k->wk_keyix; -#if 0 - kc->hw_key_idx = /* set by hw and needs to be passed for TX */; -#endif - atomic64_set(&kc->tx_pn, k->wk_keytsc); - kc->keylen = k->wk_keylen; - memcpy(kc->key, k->wk_key, k->wk_keylen); + ni = ieee80211_ref_node(vap->iv_bss); + sta = ieee80211_find_sta(vif, ni->ni_bssid); + kcf = NULL; + + if (sta == NULL) { + ic_printf(ic, "%s: sta %6D not found\n", __func__, ni->ni_bssid, ":"); + return (0); + } + lsta = STA_TO_LSTA(sta); + + if (lsta->kc[k->wk_keyix] != NULL) { + IMPROVE("Still in firmware? Del first. Can we assert this cannot happen?"); + LKPI_80211_TRACE_CRYPTO("sta %6D found with key information", ni->ni_bssid, ":"); - switch (kc->cipher) { + free(lsta->kc[k->wk_keyix], M_LKPI80211); + lsta->kc[k->wk_keyix] = NULL; /* safeguard */ + } + + lcipher = lkpi_net80211_to_l80211_cipher_suite(k->wk_cipher->ic_cipher, + k->wk_keylen); + kcf = malloc(sizeof(*kcf) + k->wk_keylen, M_LKPI80211, M_WAITOK | M_ZERO); + + if (kcf == NULL) { + return (0); + } + switch (lcipher) { case WLAN_CIPHER_SUITE_CCMP: - kc->iv_len = k->wk_cipher->ic_header; - kc->icv_len = k->wk_cipher->ic_trailer; + kcf->iv_len = k->wk_cipher->ic_header; + kcf->icv_len = k->wk_cipher->ic_trailer; break; case WLAN_CIPHER_SUITE_TKIP: default: + LKPI_80211_TRACE_CRYPTO("CIPHER SUITE %#x not supported", lcipher); IMPROVE(); return (0); - }; - - ni = vap->iv_bss; - sta = ieee80211_find_sta(vif, ni->ni_bssid); - if (sta != NULL) { - struct lkpi_sta *lsta; + } - lsta = STA_TO_LSTA(sta); - lsta->kc = kc; + kcf->cipher = lcipher; + kcf->keyidx = k->wk_keyix; + if (!IEEE80211_IS_MULTICAST(k->wk_macaddr)) { + kcf->flags = IEEE80211_KEY_FLAG_PAIRWISE; } + kcf->link_id = -1; +#if 0 + kcf->hw_key_idx = /* set by hw and needs to be passed for TX */; +#endif + atomic64_set(&kcf->tx_pn, k->wk_keytsc); + kcf->keylen = k->wk_keylen; + memcpy(kcf->key, k->wk_key, k->wk_keylen); - error = lkpi_80211_mo_set_key(hw, cmd, vif, sta, kc); + error = lkpi_80211_mo_set_key(hw, SET_KEY, vif, sta, kcf); if (error != 0) { - /* XXX-BZ leaking kc currently */ - ic_printf(ic, "%s: set_key failed: %d\n", __func__, error); + LKPI_80211_TRACE_CRYPTO("set_key cmd %d(%s) for sta %6D failed: %d", + SET_KEY, "SET", ni->ni_bssid, ":", error); return (0); - } else { - ic_printf(ic, "%s: set_key succeeded: keyidx %u hw_key_idx %u " - "flags %#10x\n", __func__, - kc->keyidx, kc->hw_key_idx, kc->flags); - return (1); } -} -static int -lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) -{ + LKPI_80211_TRACE_CRYPTO("set_key cmd %d(%s) for sta %6D succeeded: " + "kcf %p keyidx %u hw_key_idx %u flags %#x", SET_KEY, "SET", + ni->ni_bssid, ":", kcf, kcf->keyidx, kcf->hw_key_idx, kcf->flags); - /* XXX-BZ one day we should replace this iterating over VIFs, or node list? */ - return (_lkpi_iv_key_set_delete(vap, k, DISABLE_KEY)); + lsta->kc[k->wk_keyix] = kcf; + +#if 0 + /* Make sure we get the delete callback? */ + k->wk_flags |= IEEE80211_KEY_DEVKEY; +#endif + return (1); } + static int lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) { - return (_lkpi_iv_key_set_delete(vap, k, SET_KEY)); + return (_lkpi_iv_key_set(vap, k)); } -#endif +#endif /* LKPI_80211_HW_CRYPTO */ static u_int lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt) @@ -3572,9 +3670,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m) { struct ieee80211_node *ni; -#ifndef LKPI_80211_HW_CRYPTO struct ieee80211_frame *wh; -#endif struct ieee80211_key *k; struct sk_buff *skb; struct ieee80211com *ic; @@ -3598,10 +3694,10 @@ #endif ni = lsta->ni; + wh = mtod(m, struct ieee80211_frame *); k = NULL; #ifndef LKPI_80211_HW_CRYPTO /* Encrypt the frame if need be; XXX-BZ info->control.hw_key. */ - wh = mtod(m, struct ieee80211_frame *); if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { /* Retrieve key for TX && do software encryption. */ k = ieee80211_crypto_encap(ni, m); @@ -3708,7 +3804,20 @@ sta = LSTA_TO_STA(lsta); #ifdef LKPI_80211_HW_CRYPTO - info->control.hw_key = lsta->kc; + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_crypto_get_txkey(ni, m); + LKPI_80211_TRACE_CRYPTO("use key %p wk_keyix %u for " + "mbuf %p", k, k->wk_keyix, m); + + if (k != NULL && k->wk_keyix != IEEE80211_KEYIX_NONE) { + LKPI_80211_TRACE_CRYPTO("use lsta->kc[%u]:%p to " + "control.hw_key for mbuf %p", k->wk_keyix, + lsta->kc[k->wk_keyix], m); + info->control.hw_key = lsta->kc[k->wk_keyix]; + } else { + info->control.hw_key = NULL; + } + } #endif IMPROVE(); @@ -5011,6 +5120,29 @@ rx_stats.c_freq = rx_status->freq; rx_stats.c_ieee = ieee80211_mhz2ieee(rx_stats.c_freq, rx_stats.c_band); + /* + * We only need these for LKPI_80211_HW_CRYPTO in theory but in + * case the hardware does something we do not expect always leave + * these enabled. Leaving this as documentation. + */ +#if defined(LKPI_80211_HW_CRYPTO) || 1 + if (rx_status->flag & RX_FLAG_DECRYPTED) + rx_stats.c_pktflags |= IEEE80211_RX_F_DECRYPTED; + if (rx_status->flag & RX_FLAG_MMIC_STRIPPED) + rx_stats.c_pktflags |= IEEE80211_RX_F_MMIC_STRIP; + if (rx_status->flag & RX_FLAG_MIC_STRIPPED) { + IMPROVE("WARNING: no direct mapping for RX_FLAG_MIC_STRIPPED in net80211"); + rx_stats.c_pktflags |= IEEE80211_RX_F_MMIC_STRIP; + } + if (rx_status->flag & RX_FLAG_IV_STRIPPED) + rx_stats.c_pktflags |= IEEE80211_RX_F_IV_STRIP; + if (rx_status->flag & RX_FLAG_MMIC_ERROR) + rx_stats.c_pktflags |= IEEE80211_RX_F_FAIL_MIC; + if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC) + rx_stats.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC; + IMPROVE("map as many RX_FLAG_ -> IEEE80211_RX_F_ as possible"); +#endif + /* XXX (*sta_statistics)() to get to some of that? */ /* XXX-BZ dump the FreeBSD version of rx_stats as well! */