summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2005-07-11 03:06:23 +0000
committersam <sam@FreeBSD.org>2005-07-11 03:06:23 +0000
commit097175bde24a7f26bdd9d670a346922a3b1f0b6e (patch)
treee161b84d2b2b726db2a179f7ca323b7b515c3605 /sys/net80211
parente1d30f6c5644dd6c792aac5af1c492fedb704175 (diff)
downloadFreeBSD-src-097175bde24a7f26bdd9d670a346922a3b1f0b6e.zip
FreeBSD-src-097175bde24a7f26bdd9d670a346922a3b1f0b6e.tar.gz
Handle encrypt of arbitarily fragmented mbuf chains: previously
we bailed if we couldn't collect the 16-bytes of data required for an aes block cipher in 2 mbufs; now we deal with it. While here make space accounting signed so a sanity check does the right thing for malformed mbuf chains. Approved by: re (scottl)
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_crypto_ccmp.c86
1 files changed, 68 insertions, 18 deletions
diff --git a/sys/net80211/ieee80211_crypto_ccmp.c b/sys/net80211/ieee80211_crypto_ccmp.c
index 6c28c67..d0ccc93 100644
--- a/sys/net80211/ieee80211_crypto_ccmp.c
+++ b/sys/net80211/ieee80211_crypto_ccmp.c
@@ -401,11 +401,10 @@ ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
struct ccmp_ctx *ctx = key->wk_private;
struct ieee80211_frame *wh;
struct mbuf *m = m0;
- int data_len, i;
+ int data_len, i, space;
uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN],
e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN];
uint8_t *pos;
- u_int space;
ctx->cc_ic->ic_stats.is_crypto_ccmp++;
@@ -444,27 +443,75 @@ ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
}
if (space != 0) {
uint8_t *pos_next;
- u_int space_next;
- u_int len;
+ int space_next;
+ int len, dl, sp;
+ struct mbuf *n;
/*
- * Block straddles buffers, split references. We
- * do not handle splits that require >2 buffers.
+ * Block straddles one or more mbufs, gather data
+ * into the block buffer b, apply the cipher, then
+ * scatter the results back into the mbuf chain.
+ * The buffer will automatically get space bytes
+ * of data at offset 0 copied in+out by the
+ * CCMP_ENCRYPT request so we must take care of
+ * the remaining data.
*/
- pos_next = mtod(m, uint8_t *);
- len = min(data_len, AES_BLOCK_LEN);
- space_next = len > space ? len - space : 0;
- KASSERT(m->m_len >= space_next,
- ("not enough data in following buffer, "
- "m_len %u need %u\n", m->m_len, space_next));
+ n = m;
+ dl = data_len;
+ sp = space;
+ for (;;) {
+ pos_next = mtod(n, uint8_t *);
+ len = min(dl, AES_BLOCK_LEN);
+ space_next = len > sp ? len - sp : 0;
+ if (n->m_len >= space_next) {
+ /*
+ * This mbuf has enough data; just grab
+ * what we need and stop.
+ */
+ xor_block(b+sp, pos_next, space_next);
+ break;
+ }
+ /*
+ * This mbuf's contents are insufficient,
+ * take 'em all and prepare to advance to
+ * the next mbuf.
+ */
+ xor_block(b+sp, pos_next, n->m_len);
+ sp += n->m_len, dl -= n->m_len;
+ n = n->m_next;
+ if (n == NULL)
+ break;
+ }
- xor_block(b+space, pos_next, space_next);
CCMP_ENCRYPT(i, b, b0, pos, e, space);
- xor_block(pos_next, e+space, space_next);
- data_len -= len;
- /* XXX could check for data_len <= 0 */
- i++;
+ /* NB: just like above, but scatter data to mbufs */
+ dl = data_len;
+ sp = space;
+ for (;;) {
+ pos_next = mtod(m, uint8_t *);
+ len = min(dl, AES_BLOCK_LEN);
+ space_next = len > sp ? len - sp : 0;
+ if (m->m_len >= space_next) {
+ xor_block(pos_next, e+sp, space_next);
+ break;
+ }
+ xor_block(pos_next, e+sp, m->m_len);
+ sp += m->m_len, dl -= m->m_len;
+ m = m->m_next;
+ if (m == NULL)
+ goto done;
+ }
+ /*
+ * Do bookkeeping. m now points to the last mbuf
+ * we grabbed data from. We know we consumed a
+ * full block of data as otherwise we'd have hit
+ * the end of the mbuf chain, so deduct from data_len.
+ * Otherwise advance the block number (i) and setup
+ * pos+space to reflect contents of the new mbuf.
+ */
+ data_len -= AES_BLOCK_LEN;
+ i++;
pos = pos_next + space_next;
space = m->m_len - space_next;
} else {
@@ -475,6 +522,7 @@ ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
space = m->m_len;
}
}
+done:
/* tack on MIC */
xor_block(b, s0, ccmp.ic_trailer);
return m_append(m0, ccmp.ic_trailer, b);
@@ -540,7 +588,9 @@ ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen
/*
* Block straddles buffers, split references. We
- * do not handle splits that require >2 buffers.
+ * do not handle splits that require >2 buffers
+ * since rx'd frames are never badly fragmented
+ * because drivers typically recv in clusters.
*/
pos_next = mtod(m, uint8_t *);
len = min(data_len, AES_BLOCK_LEN);
OpenPOWER on IntegriCloud