aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_sta.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net80211/ieee80211_sta.c')
-rw-r--r--sys/net80211/ieee80211_sta.c60
1 files changed, 53 insertions, 7 deletions
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 04fafe9c9772..dd9ef6e4d21a 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -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) {
/*
@@ -724,6 +734,21 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
}
/*
+ * 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, 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;
}