aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_crypto_tkip.c
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2016-11-19 02:00:24 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2016-11-19 02:00:24 +0000
commitfe75b45213a403dc13c2e8a3bef5c83fa3b8225c (patch)
tree9b6b7d0214b2ec19cbc742b5e35afe97bc895dc8 /sys/net80211/ieee80211_crypto_tkip.c
parentc49cf11473dfae9cae91ef4267b852116d089e50 (diff)
[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
Notes
Notes: svn path=/head/; revision=308823
Diffstat (limited to 'sys/net80211/ieee80211_crypto_tkip.c')
-rw-r--r--sys/net80211/ieee80211_crypto_tkip.c77
1 files changed, 74 insertions, 3 deletions
diff --git a/sys/net80211/ieee80211_crypto_tkip.c b/sys/net80211/ieee80211_crypto_tkip.c
index 8b33a7919762..20258fa05e37 100644
--- a/sys/net80211/ieee80211_crypto_tkip.c
+++ b/sys/net80211/ieee80211_crypto_tkip.c
@@ -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 - 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, 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;
}