From owner-svn-src-all@freebsd.org Sat Nov 19 02:00:26 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 85DE8C49CFC; Sat, 19 Nov 2016 02:00:26 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 51E56154D; Sat, 19 Nov 2016 02:00:26 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAJ20P3U099361; Sat, 19 Nov 2016 02:00:25 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAJ20Ovm099353; Sat, 19 Nov 2016 02:00:24 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <201611190200.uAJ20Ovm099353@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Sat, 19 Nov 2016 02:00:24 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r308823 - head/sys/net80211 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 19 Nov 2016 02:00:26 -0000 Author: adrian Date: Sat Nov 19 02:00:24 2016 New Revision: 308823 URL: https://svnweb.freebsd.org/changeset/base/308823 Log: [net80211] handle hardware encryption offload in the receive path * teach the crypto modules about receive offload - although I have to do some further reviewing in places where we /can't/ have an RX key * teach the RX data path about receive offload encryption - check the flag, handle NULL key, do decap and checking as appropriate. Tested: * iwn(4), STA mode * ath(4), STA and AP mode * ath10k port, STA mode (hardware encryption) Reviewed by: avos Differential Revision: https://reviews.freebsd.org/D8533 Modified: head/sys/net80211/ieee80211_adhoc.c head/sys/net80211/ieee80211_crypto.c head/sys/net80211/ieee80211_crypto.h head/sys/net80211/ieee80211_crypto_ccmp.c head/sys/net80211/ieee80211_crypto_tkip.c head/sys/net80211/ieee80211_hostap.c head/sys/net80211/ieee80211_sta.c head/sys/net80211/ieee80211_wds.c Modified: head/sys/net80211/ieee80211_adhoc.c ============================================================================== --- head/sys/net80211/ieee80211_adhoc.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_adhoc.c Sat Nov 19 02:00:24 2016 (r308823) @@ -316,6 +316,16 @@ adhoc_input(struct ieee80211_node *ni, s int hdrspace, need_tap = 1; /* mbuf need to be tapped. */ uint8_t dir, type, subtype, qos; uint8_t *bssid; + int is_hw_decrypted = 0; + int has_decrypted = 0; + + /* + * Some devices do hardware decryption all the way through + * to pretending the frame wasn't encrypted in the first place. + * So, tag it appropriately so it isn't discarded inappropriately. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED)) + is_hw_decrypted = 1; if (m->m_flags & M_AMPDU_MPDU) { /* @@ -479,7 +489,7 @@ adhoc_input(struct ieee80211_node *ni, s * crypto cipher modules used to do delayed update * of replay sequence numbers. */ - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + if (is_hw_decrypted || wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { /* * Discard encrypted frames when privacy is off. @@ -490,14 +500,14 @@ adhoc_input(struct ieee80211_node *ni, s IEEE80211_NODE_STAT(ni, rx_noprivacy); goto out; } - key = ieee80211_crypto_decap(ni, m, hdrspace); - if (key == NULL) { + if (ieee80211_crypto_decap(ni, m, hdrspace, &key) == 0) { /* NB: stats+msgs handled in crypto_decap */ IEEE80211_NODE_STAT(ni, rx_wepfail); goto out; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + has_decrypted = 1; } else { /* XXX M_WEP and IEEE80211_F_PRIVACY */ key = NULL; @@ -528,7 +538,7 @@ adhoc_input(struct ieee80211_node *ni, s /* * Next strip any MSDU crypto bits. */ - if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) { + if (!ieee80211_crypto_demic(vap, key, m, 0)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ni->ni_macaddr, "data", "%s", "demic error"); vap->iv_stats.is_rx_demicfail++; @@ -582,7 +592,8 @@ adhoc_input(struct ieee80211_node *ni, s * any non-PAE frames received without encryption. */ if ((vap->iv_flags & IEEE80211_F_DROPUNENC) && - (key == NULL && (m->m_flags & M_WEP) == 0) && + ((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) && + (is_hw_decrypted == 0) && eh->ether_type != htons(ETHERTYPE_PAE)) { /* * Drop unencrypted frames. Modified: head/sys/net80211/ieee80211_crypto.c ============================================================================== --- head/sys/net80211/ieee80211_crypto.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_crypto.c Sat Nov 19 02:00:24 2016 (r308823) @@ -580,8 +580,9 @@ ieee80211_crypto_encap(struct ieee80211_ * Validate and strip privacy headers (and trailer) for a * received frame that has the WEP/Privacy bit set. */ -struct ieee80211_key * -ieee80211_crypto_decap(struct ieee80211_node *ni, struct mbuf *m, int hdrlen) +int +ieee80211_crypto_decap(struct ieee80211_node *ni, struct mbuf *m, int hdrlen, + struct ieee80211_key **key) { #define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) #define IEEE80211_WEP_MINLEN \ @@ -590,16 +591,38 @@ ieee80211_crypto_decap(struct ieee80211_ struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_key *k; struct ieee80211_frame *wh; + const struct ieee80211_rx_stats *rxs; const struct ieee80211_cipher *cip; uint8_t keyid; + /* + * Check for hardware decryption and IV stripping. + * If the IV is stripped then we definitely can't find a key. + * Set the key to NULL but return true; upper layers + * will need to handle a NULL key for a successful + * decrypt. + */ + rxs = ieee80211_get_rx_params_ptr(m); + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED)) { + if (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) { + /* + * Hardware decrypted, IV stripped. + * We can't find a key with a stripped IV. + * Return successful. + */ + *key = NULL; + return (1); + } + } + /* NB: this minimum size data frame could be bigger */ if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, "%s: WEP data frame too short, len %u\n", __func__, m->m_pkthdr.len); vap->iv_stats.is_rx_tooshort++; /* XXX need unique stat? */ - return NULL; + *key = NULL; + return (0); } /* @@ -625,15 +648,29 @@ ieee80211_crypto_decap(struct ieee80211_ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, "unable to pullup %s header", cip->ic_name); vap->iv_stats.is_rx_wepfail++; /* XXX */ - return NULL; + *key = NULL; + return (0); + } + + /* + * Attempt decryption. + * + * If we fail then don't return the key - return NULL + * and an error. + */ + if (cip->ic_decap(k, m, hdrlen)) { + /* success */ + *key = k; + return (1); } - return (cip->ic_decap(k, m, hdrlen) ? k : NULL); + /* Failure */ + *key = NULL; + return (0); #undef IEEE80211_WEP_MINLEN #undef IEEE80211_WEP_HDRLEN } - /* * Check and remove any MIC. */ Modified: head/sys/net80211/ieee80211_crypto.h ============================================================================== --- head/sys/net80211/ieee80211_crypto.h Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_crypto.h Sat Nov 19 02:00:24 2016 (r308823) @@ -114,7 +114,8 @@ struct ieee80211_key { #define IEEE80211_KEY_DEVICE /* flags owned by device driver */\ (IEEE80211_KEY_DEVKEY|IEEE80211_KEY_CIPHER0|IEEE80211_KEY_CIPHER1| \ - IEEE80211_KEY_SWCRYPT|IEEE80211_KEY_SWMIC) + IEEE80211_KEY_SWCRYPT|IEEE80211_KEY_SWMIC|IEEE80211_KEY_NOIV | \ + IEEE80211_KEY_NOIVMGT|IEEE80211_KEY_NOMIC|IEEE80211_KEY_NOMICMGT) #define IEEE80211_KEY_BITS \ "\20\1XMIT\2RECV\3GROUP\4SWENCRYPT\5SWDECRYPT\6SWENMIC\7SWDEMIC" \ @@ -207,8 +208,8 @@ struct ieee80211_key *ieee80211_crypto_g struct mbuf *); struct ieee80211_key *ieee80211_crypto_encap(struct ieee80211_node *, struct mbuf *); -struct ieee80211_key *ieee80211_crypto_decap(struct ieee80211_node *, - struct mbuf *, int); +int ieee80211_crypto_decap(struct ieee80211_node *, + struct mbuf *, int, struct ieee80211_key **); int ieee80211_crypto_demic(struct ieee80211vap *vap, struct ieee80211_key *k, struct mbuf *, int); /* Modified: head/sys/net80211/ieee80211_crypto_ccmp.c ============================================================================== --- head/sys/net80211/ieee80211_crypto_ccmp.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_crypto_ccmp.c Sat Nov 19 02:00:24 2016 (r308823) @@ -162,12 +162,27 @@ ccmp_setiv(struct ieee80211_key *k, uint static int ccmp_encap(struct ieee80211_key *k, struct mbuf *m) { + const struct ieee80211_frame *wh; struct ccmp_ctx *ctx = k->wk_private; struct ieee80211com *ic = ctx->cc_ic; uint8_t *ivp; int hdrlen; + int is_mgmt; hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); + wh = mtod(m, const struct ieee80211_frame *); + is_mgmt = IEEE80211_IS_MGMT(wh); + + /* + * Check to see if we need to insert IV/MIC. + * + * Some offload devices don't require the IV to be inserted + * as part of the hardware encryption. + */ + if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT)) + return 1; + if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV)) + return 1; /* * Copy down 802.11 header and add the IV, KeyID, and ExtIV. @@ -217,12 +232,18 @@ READ_6(uint8_t b0, uint8_t b1, uint8_t b static int ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) { + const struct ieee80211_rx_stats *rxs; struct ccmp_ctx *ctx = k->wk_private; struct ieee80211vap *vap = ctx->cc_vap; struct ieee80211_frame *wh; uint8_t *ivp, tid; uint64_t pn; + rxs = ieee80211_get_rx_params_ptr(m); + + if ((rxs != NULL) & (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP)) + goto finish; + /* * Header should have extended IV and sequence number; * verify the former and validate the latter. @@ -261,17 +282,28 @@ ccmp_decap(struct ieee80211_key *k, stru !ccmp_decrypt(k, pn, m, hdrlen)) return 0; +finish: /* * Copy up 802.11 header and strip crypto bits. */ - ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, hdrlen); - m_adj(m, ccmp.ic_header); - m_adj(m, -ccmp.ic_trailer); + if (! ((rxs != NULL) & (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { + ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, + hdrlen); + m_adj(m, ccmp.ic_header); + } + + /* + * XXX TODO: see if MMIC_STRIP also covers CCMP MIC trailer. + */ + if (! ((rxs != NULL) & (rxs->c_pktflags & IEEE80211_RX_F_MMIC_STRIP))) + m_adj(m, -ccmp.ic_trailer); /* * Ok to update rsc now. */ - k->wk_keyrsc[tid] = pn; + if (! ((rxs != NULL) & (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { + k->wk_keyrsc[tid] = pn; + } return 1; } Modified: head/sys/net80211/ieee80211_crypto_tkip.c ============================================================================== --- head/sys/net80211/ieee80211_crypto_tkip.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_crypto_tkip.c Sat Nov 19 02:00:24 2016 (r308823) @@ -177,8 +177,13 @@ tkip_encap(struct ieee80211_key *k, stru struct tkip_ctx *ctx = k->wk_private; struct ieee80211vap *vap = ctx->tc_vap; struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_frame *wh; uint8_t *ivp; int hdrlen; + int is_mgmt; + + wh = mtod(m, struct ieee80211_frame *); + is_mgmt = IEEE80211_IS_MGMT(wh); /* * Handle TKIP counter measures requirement. @@ -193,6 +198,16 @@ tkip_encap(struct ieee80211_key *k, stru vap->iv_stats.is_crypto_tkipcm++; return 0; } + + /* + * Check to see whether IV needs to be included. + */ + if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT)) + return 1; + if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV)) + return 1; + + hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); /* @@ -224,6 +239,19 @@ static int tkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force) { struct tkip_ctx *ctx = k->wk_private; + struct ieee80211_frame *wh; + int is_mgmt; + + wh = mtod(m, struct ieee80211_frame *); + is_mgmt = IEEE80211_IS_MGMT(wh); + + /* + * Check to see whether MIC needs to be included. + */ + if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOMICMGT)) + return 1; + if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOMIC)) + return 1; if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) { struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); @@ -259,11 +287,20 @@ READ_6(uint8_t b0, uint8_t b1, uint8_t b static int tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) { + const struct ieee80211_rx_stats *rxs; struct tkip_ctx *ctx = k->wk_private; struct ieee80211vap *vap = ctx->tc_vap; struct ieee80211_frame *wh; uint8_t *ivp, tid; + rxs = ieee80211_get_rx_params_ptr(m); + + /* + * If IV has been stripped, we skip most of the below. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP)) + goto finish; + /* * Header should have extended IV and sequence number; * verify the former and validate the latter. @@ -318,11 +355,22 @@ tkip_decap(struct ieee80211_key *k, stru !tkip_decrypt(ctx, k, m, hdrlen)) return 0; +finish: + + /* + * Copy up 802.11 header and strip crypto bits - but only if we + * are required to. + */ + if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { + memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), + hdrlen); + m_adj(m, tkip.ic_header); + } + /* - * Copy up 802.11 header and strip crypto bits. + * XXX TODO: do we need an option to potentially not strip the + * WEP trailer? Does "MMIC_STRIP" also mean this? Or? */ - memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen); - m_adj(m, tkip.ic_header); m_adj(m, -tkip.ic_trailer); return 1; @@ -334,11 +382,33 @@ tkip_decap(struct ieee80211_key *k, stru static int tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force) { + const struct ieee80211_rx_stats *rxs; struct tkip_ctx *ctx = k->wk_private; struct ieee80211_frame *wh; uint8_t tid; wh = mtod(m, struct ieee80211_frame *); + rxs = ieee80211_get_rx_params_ptr(m); + + /* + * If we are told about a MIC failure from the driver, + * directly notify as a michael failure to the upper + * layers. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_FAIL_MIC)) { + struct ieee80211vap *vap = ctx->tc_vap; + ieee80211_notify_michael_failure(vap, wh, + k->wk_rxkeyix != IEEE80211_KEYIX_NONE ? + k->wk_rxkeyix : k->wk_keyix); + return 0; + } + + /* + * If IV has been stripped, we skip most of the below. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MMIC_STRIP)) + goto finish; + if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) { struct ieee80211vap *vap = ctx->tc_vap; int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh); @@ -371,6 +441,7 @@ tkip_demic(struct ieee80211_key *k, stru tid = ieee80211_gettid(wh); k->wk_keyrsc[tid] = ctx->rx_rsc; +finish: return 1; } Modified: head/sys/net80211/ieee80211_hostap.c ============================================================================== --- head/sys/net80211/ieee80211_hostap.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_hostap.c Sat Nov 19 02:00:24 2016 (r308823) @@ -479,6 +479,16 @@ hostap_input(struct ieee80211_node *ni, int hdrspace, need_tap = 1; /* mbuf need to be tapped. */ uint8_t dir, type, subtype, qos; uint8_t *bssid; + int is_hw_decrypted = 0; + int has_decrypted = 0; + + /* + * Some devices do hardware decryption all the way through + * to pretending the frame wasn't encrypted in the first place. + * So, tag it appropriately so it isn't discarded inappropriately. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED)) + is_hw_decrypted = 1; if (m->m_flags & M_AMPDU_MPDU) { /* @@ -668,7 +678,7 @@ hostap_input(struct ieee80211_node *ni, * crypto cipher modules used to do delayed update * of replay sequence numbers. */ - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + if (is_hw_decrypted || wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { /* * Discard encrypted frames when privacy is off. @@ -679,14 +689,14 @@ hostap_input(struct ieee80211_node *ni, IEEE80211_NODE_STAT(ni, rx_noprivacy); goto out; } - key = ieee80211_crypto_decap(ni, m, hdrspace); - if (key == NULL) { + if (ieee80211_crypto_decap(ni, m, hdrspace, &key) == 0) { /* NB: stats+msgs handled in crypto_decap */ IEEE80211_NODE_STAT(ni, rx_wepfail); goto out; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + has_decrypted = 1; } else { /* XXX M_WEP and IEEE80211_F_PRIVACY */ key = NULL; @@ -769,7 +779,8 @@ hostap_input(struct ieee80211_node *ni, * any non-PAE frames received without encryption. */ if ((vap->iv_flags & IEEE80211_F_DROPUNENC) && - (key == NULL && (m->m_flags & M_WEP) == 0) && + ((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) && + (is_hw_decrypted == 0) && eh->ether_type != htons(ETHERTYPE_PAE)) { /* * Drop unencrypted frames. @@ -851,13 +862,13 @@ hostap_input(struct ieee80211_node *ni, goto out; } hdrspace = ieee80211_hdrspace(ic, wh); - key = ieee80211_crypto_decap(ni, m, hdrspace); - if (key == NULL) { + if (ieee80211_crypto_decap(ni, m, hdrspace, &key) == 0) { /* NB: stats+msgs handled in crypto_decap */ goto out; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + has_decrypted = 1; } /* * Pass the packet to radiotap before calling iv_recv_mgmt(). Modified: head/sys/net80211/ieee80211_sta.c ============================================================================== --- head/sys/net80211/ieee80211_sta.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_sta.c Sat Nov 19 02:00:24 2016 (r308823) @@ -546,6 +546,16 @@ sta_input(struct ieee80211_node *ni, str int hdrspace, need_tap = 1; /* mbuf need to be tapped. */ uint8_t dir, type, subtype, qos; uint8_t *bssid; + int is_hw_decrypted = 0; + int has_decrypted = 0; + + /* + * Some devices do hardware decryption all the way through + * to pretending the frame wasn't encrypted in the first place. + * So, tag it appropriately so it isn't discarded inappropriately. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED)) + is_hw_decrypted = 1; if (m->m_flags & M_AMPDU_MPDU) { /* @@ -724,6 +734,21 @@ sta_input(struct ieee80211_node *ni, str } /* + * Handle privacy requirements for hardware decryption + * devices. + * + * For those devices, a handful of things happen. + * + * + If IV has been stripped, then we can't run + * ieee80211_crypto_decap() - none of the key + * + If MIC has been stripped, we can't validate + * MIC here. + * + If MIC fails, then we need to communicate a + * MIC failure up to the stack - but we don't know + * which key was used. + */ + + /* * Handle privacy requirements. Note that we * must not be preempted from here until after * we (potentially) call ieee80211_crypto_demic; @@ -731,7 +756,7 @@ sta_input(struct ieee80211_node *ni, str * crypto cipher modules used to do delayed update * of replay sequence numbers. */ - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + if (is_hw_decrypted || wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { /* * Discard encrypted frames when privacy is off. @@ -742,14 +767,14 @@ sta_input(struct ieee80211_node *ni, str IEEE80211_NODE_STAT(ni, rx_noprivacy); goto out; } - key = ieee80211_crypto_decap(ni, m, hdrspace); - if (key == NULL) { + if (ieee80211_crypto_decap(ni, m, hdrspace, &key) == 0) { /* NB: stats+msgs handled in crypto_decap */ IEEE80211_NODE_STAT(ni, rx_wepfail); goto out; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + has_decrypted = 1; } else { /* XXX M_WEP and IEEE80211_F_PRIVACY */ key = NULL; @@ -779,8 +804,13 @@ sta_input(struct ieee80211_node *ni, str /* * Next strip any MSDU crypto bits. + * + * Note: we can't do MIC stripping/verification if the + * upper layer has stripped it. We have to check MIC + * ourselves. So, key may be NULL, but we have to check + * the RX status. */ - if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) { + if (!ieee80211_crypto_demic(vap, key, m, 0)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ni->ni_macaddr, "data", "%s", "demic error"); vap->iv_stats.is_rx_demicfail++; @@ -834,7 +864,8 @@ sta_input(struct ieee80211_node *ni, str * any non-PAE frames received without encryption. */ if ((vap->iv_flags & IEEE80211_F_DROPUNENC) && - (key == NULL && (m->m_flags & M_WEP) == 0) && + ((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) && + (is_hw_decrypted == 0) && eh->ether_type != htons(ETHERTYPE_PAE)) { /* * Drop unencrypted frames. @@ -883,6 +914,16 @@ sta_input(struct ieee80211_node *ni, str ether_sprintf(wh->i_addr2), rssi); } #endif + + /* + * Note: See above for hardware offload privacy requirements. + * It also applies here. + */ + + /* + * Again, having encrypted flag set check would be good, but + * then we have to also handle crypto_decap() like above. + */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) { /* @@ -905,11 +946,16 @@ sta_input(struct ieee80211_node *ni, str goto out; } hdrspace = ieee80211_hdrspace(ic, wh); - key = ieee80211_crypto_decap(ni, m, hdrspace); - if (key == NULL) { + + /* + * Again, if IV/MIC was stripped, then this whole + * setup will fail. That's going to need some poking. + */ + if (ieee80211_crypto_decap(ni, m, hdrspace, &key) == 0) { /* NB: stats+msgs handled in crypto_decap */ goto out; } + has_decrypted = 1; wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; } Modified: head/sys/net80211/ieee80211_wds.c ============================================================================== --- head/sys/net80211/ieee80211_wds.c Sat Nov 19 01:51:56 2016 (r308822) +++ head/sys/net80211/ieee80211_wds.c Sat Nov 19 02:00:24 2016 (r308823) @@ -417,6 +417,16 @@ wds_input(struct ieee80211_node *ni, str struct ether_header *eh; int hdrspace, need_tap = 1; /* mbuf need to be tapped. */ uint8_t dir, type, subtype, qos; + int is_hw_decrypted = 0; + int has_decrypted = 0; + + /* + * Some devices do hardware decryption all the way through + * to pretending the frame wasn't encrypted in the first place. + * So, tag it appropriately so it isn't discarded inappropriately. + */ + if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED)) + is_hw_decrypted = 1; if (m->m_flags & M_AMPDU_MPDU) { /* @@ -544,7 +554,7 @@ wds_input(struct ieee80211_node *ni, str * crypto cipher modules used to do delayed update * of replay sequence numbers. */ - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + if (is_hw_decrypted || wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { /* * Discard encrypted frames when privacy is off. @@ -555,14 +565,14 @@ wds_input(struct ieee80211_node *ni, str IEEE80211_NODE_STAT(ni, rx_noprivacy); goto out; } - key = ieee80211_crypto_decap(ni, m, hdrspace); - if (key == NULL) { + if (ieee80211_crypto_decap(ni, m, hdrspace, &key) == 0) { /* NB: stats+msgs handled in crypto_decap */ IEEE80211_NODE_STAT(ni, rx_wepfail); goto out; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + has_decrypted = 1; } else { /* XXX M_WEP and IEEE80211_F_PRIVACY */ key = NULL; @@ -593,7 +603,7 @@ wds_input(struct ieee80211_node *ni, str /* * Next strip any MSDU crypto bits. */ - if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) { + if (!ieee80211_crypto_demic(vap, key, m, 0)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ni->ni_macaddr, "data", "%s", "demic error"); vap->iv_stats.is_rx_demicfail++; @@ -647,7 +657,8 @@ wds_input(struct ieee80211_node *ni, str * any non-PAE frames received without encryption. */ if ((vap->iv_flags & IEEE80211_F_DROPUNENC) && - (key == NULL && (m->m_flags & M_WEP) == 0) && + ((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) && + (is_hw_decrypted == 0) && eh->ether_type != htons(ETHERTYPE_PAE)) { /* * Drop unencrypted frames.