[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
This commit is contained in:
parent
50924d7c9b
commit
6e8bf3b9a6
@ -316,6 +316,16 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
* 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, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
/*
|
||||
* 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, struct mbuf *m,
|
||||
* 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.
|
||||
|
@ -580,8 +580,9 @@ ieee80211_crypto_encap(struct ieee80211_node *ni, struct mbuf *m)
|
||||
* 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_node *ni, struct mbuf *m, int hdrlen)
|
||||
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_node *ni, struct mbuf *m, int hdrlen)
|
||||
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);
|
||||
}
|
||||
|
||||
return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* Failure */
|
||||
*key = NULL;
|
||||
return (0);
|
||||
#undef IEEE80211_WEP_MINLEN
|
||||
#undef IEEE80211_WEP_HDRLEN
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check and remove any MIC.
|
||||
*/
|
||||
|
@ -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_get_txkey(struct ieee80211_node *,
|
||||
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);
|
||||
/*
|
||||
|
@ -162,12 +162,27 @@ ccmp_setiv(struct ieee80211_key *k, uint8_t *ivp)
|
||||
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 b2, uint8_t b3, uint8_t b4, uint8_t b5)
|
||||
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, struct mbuf *m, int hdrlen)
|
||||
!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;
|
||||
}
|
||||
|
@ -177,8 +177,13 @@ tkip_encap(struct ieee80211_key *k, struct mbuf *m)
|
||||
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, struct mbuf *m)
|
||||
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 b2, uint8_t b3, uint8_t b4, uint8_t b5)
|
||||
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, struct mbuf *m, int hdrlen)
|
||||
!tkip_decrypt(ctx, k, m, hdrlen))
|
||||
return 0;
|
||||
|
||||
finish:
|
||||
|
||||
/*
|
||||
* Copy up 802.11 header and strip crypto bits.
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, struct mbuf *m, int hdrlen)
|
||||
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, struct mbuf *m, int force)
|
||||
tid = ieee80211_gettid(wh);
|
||||
k->wk_keyrsc[tid] = ctx->rx_rsc;
|
||||
|
||||
finish:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -479,6 +479,16 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
* 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, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
* 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, struct mbuf *m,
|
||||
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().
|
||||
|
@ -546,6 +546,16 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
|
||||
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) {
|
||||
/*
|
||||
@ -723,6 +733,21 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -731,7 +756,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
|
||||
* 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, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
|
||||
/*
|
||||
* 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, struct mbuf *m,
|
||||
* 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, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
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;
|
||||
}
|
||||
|
@ -417,6 +417,16 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
* 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, struct mbuf *m,
|
||||
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, struct mbuf *m,
|
||||
/*
|
||||
* 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, struct mbuf *m,
|
||||
* 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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user