ieee80211_crypto_ccmp.c revision 206457
1/*-
2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto_ccmp.c 206457 2010-04-10 13:54:00Z bschmidt $");
28
29/*
30 * IEEE 802.11i AES-CCMP crypto support.
31 *
32 * Part of this module is derived from similar code in the Host
33 * AP driver. The code is used with the consent of the author and
34 * it's license is included below.
35 */
36#include "opt_wlan.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/mbuf.h>
41#include <sys/malloc.h>
42#include <sys/kernel.h>
43#include <sys/module.h>
44
45#include <sys/socket.h>
46
47#include <net/if.h>
48#include <net/if_media.h>
49#include <net/ethernet.h>
50
51#include <net80211/ieee80211_var.h>
52
53#include <crypto/rijndael/rijndael.h>
54
55#define AES_BLOCK_LEN 16
56
57struct ccmp_ctx {
58	struct ieee80211vap *cc_vap;	/* for diagnostics+statistics */
59	struct ieee80211com *cc_ic;
60	rijndael_ctx	     cc_aes;
61};
62
63static	void *ccmp_attach(struct ieee80211vap *, struct ieee80211_key *);
64static	void ccmp_detach(struct ieee80211_key *);
65static	int ccmp_setkey(struct ieee80211_key *);
66static	int ccmp_encap(struct ieee80211_key *k, struct mbuf *, uint8_t keyid);
67static	int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
68static	int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
69static	int ccmp_demic(struct ieee80211_key *, struct mbuf *, int);
70
71static const struct ieee80211_cipher ccmp = {
72	.ic_name	= "AES-CCM",
73	.ic_cipher	= IEEE80211_CIPHER_AES_CCM,
74	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
75			  IEEE80211_WEP_EXTIVLEN,
76	.ic_trailer	= IEEE80211_WEP_MICLEN,
77	.ic_miclen	= 0,
78	.ic_attach	= ccmp_attach,
79	.ic_detach	= ccmp_detach,
80	.ic_setkey	= ccmp_setkey,
81	.ic_encap	= ccmp_encap,
82	.ic_decap	= ccmp_decap,
83	.ic_enmic	= ccmp_enmic,
84	.ic_demic	= ccmp_demic,
85};
86
87static	int ccmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
88static	int ccmp_decrypt(struct ieee80211_key *, u_int64_t pn,
89		struct mbuf *, int hdrlen);
90
91/* number of references from net80211 layer */
92static	int nrefs = 0;
93
94static void *
95ccmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
96{
97	struct ccmp_ctx *ctx;
98
99	ctx = (struct ccmp_ctx *) malloc(sizeof(struct ccmp_ctx),
100		M_80211_CRYPTO, M_NOWAIT | M_ZERO);
101	if (ctx == NULL) {
102		vap->iv_stats.is_crypto_nomem++;
103		return NULL;
104	}
105	ctx->cc_vap = vap;
106	ctx->cc_ic = vap->iv_ic;
107	nrefs++;			/* NB: we assume caller locking */
108	return ctx;
109}
110
111static void
112ccmp_detach(struct ieee80211_key *k)
113{
114	struct ccmp_ctx *ctx = k->wk_private;
115
116	free(ctx, M_80211_CRYPTO);
117	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
118	nrefs--;			/* NB: we assume caller locking */
119}
120
121static int
122ccmp_setkey(struct ieee80211_key *k)
123{
124	struct ccmp_ctx *ctx = k->wk_private;
125
126	if (k->wk_keylen != (128/NBBY)) {
127		IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
128			"%s: Invalid key length %u, expecting %u\n",
129			__func__, k->wk_keylen, 128/NBBY);
130		return 0;
131	}
132	if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)
133		rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);
134	return 1;
135}
136
137/*
138 * Add privacy headers appropriate for the specified key.
139 */
140static int
141ccmp_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
142{
143	struct ccmp_ctx *ctx = k->wk_private;
144	struct ieee80211com *ic = ctx->cc_ic;
145	uint8_t *ivp;
146	int hdrlen;
147
148	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
149
150	/*
151	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
152	 */
153	M_PREPEND(m, ccmp.ic_header, M_NOWAIT);
154	if (m == NULL)
155		return 0;
156	ivp = mtod(m, uint8_t *);
157	ovbcopy(ivp + ccmp.ic_header, ivp, hdrlen);
158	ivp += hdrlen;
159
160	k->wk_keytsc++;		/* XXX wrap at 48 bits */
161	ivp[0] = k->wk_keytsc >> 0;		/* PN0 */
162	ivp[1] = k->wk_keytsc >> 8;		/* PN1 */
163	ivp[2] = 0;				/* Reserved */
164	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
165	ivp[4] = k->wk_keytsc >> 16;		/* PN2 */
166	ivp[5] = k->wk_keytsc >> 24;		/* PN3 */
167	ivp[6] = k->wk_keytsc >> 32;		/* PN4 */
168	ivp[7] = k->wk_keytsc >> 40;		/* PN5 */
169
170	/*
171	 * Finally, do software encrypt if neeed.
172	 */
173	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
174	    !ccmp_encrypt(k, m, hdrlen))
175		return 0;
176
177	return 1;
178}
179
180/*
181 * Add MIC to the frame as needed.
182 */
183static int
184ccmp_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
185{
186
187	return 1;
188}
189
190static __inline uint64_t
191READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
192{
193	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
194	uint16_t iv16 = (b4 << 0) | (b5 << 8);
195	return (((uint64_t)iv16) << 32) | iv32;
196}
197
198/*
199 * Validate and strip privacy headers (and trailer) for a
200 * received frame. The specified key should be correct but
201 * is also verified.
202 */
203static int
204ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
205{
206	struct ccmp_ctx *ctx = k->wk_private;
207	struct ieee80211vap *vap = ctx->cc_vap;
208	struct ieee80211_frame *wh;
209	uint8_t *ivp, tid;
210	uint64_t pn;
211
212	/*
213	 * Header should have extended IV and sequence number;
214	 * verify the former and validate the latter.
215	 */
216	wh = mtod(m, struct ieee80211_frame *);
217	ivp = mtod(m, uint8_t *) + hdrlen;
218	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
219		/*
220		 * No extended IV; discard frame.
221		 */
222		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
223			"%s", "missing ExtIV for AES-CCM cipher");
224		vap->iv_stats.is_rx_ccmpformat++;
225		return 0;
226	}
227	tid = ieee80211_gettid(wh);
228	pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
229	/*
230	 * NB: Multiple stations are using the same key in
231	 * IBSS mode, there is currently no way to sync keyrsc
232	 * counters without discarding too many frames.
233	 */
234	if (vap->iv_opmode != IEEE80211_M_IBSS &&
235	    vap->iv_opmode != IEEE80211_M_AHDEMO &&
236	    pn <= k->wk_keyrsc[tid]) {
237		/*
238		 * Replay violation.
239		 */
240		ieee80211_notify_replay_failure(vap, wh, k, pn, tid);
241		vap->iv_stats.is_rx_ccmpreplay++;
242		return 0;
243	}
244
245	/*
246	 * Check if the device handled the decrypt in hardware.
247	 * If so we just strip the header; otherwise we need to
248	 * handle the decrypt in software.  Note that for the
249	 * latter we leave the header in place for use in the
250	 * decryption work.
251	 */
252	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
253	    !ccmp_decrypt(k, pn, m, hdrlen))
254		return 0;
255
256	/*
257	 * Copy up 802.11 header and strip crypto bits.
258	 */
259	ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, hdrlen);
260	m_adj(m, ccmp.ic_header);
261	m_adj(m, -ccmp.ic_trailer);
262
263	/*
264	 * Ok to update rsc now.
265	 */
266	k->wk_keyrsc[tid] = pn;
267
268	return 1;
269}
270
271/*
272 * Verify and strip MIC from the frame.
273 */
274static int
275ccmp_demic(struct ieee80211_key *k, struct mbuf *m, int force)
276{
277	return 1;
278}
279
280static __inline void
281xor_block(uint8_t *b, const uint8_t *a, size_t len)
282{
283	int i;
284	for (i = 0; i < len; i++)
285		b[i] ^= a[i];
286}
287
288/*
289 * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
290 *
291 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
292 *
293 * This program is free software; you can redistribute it and/or modify
294 * it under the terms of the GNU General Public License version 2 as
295 * published by the Free Software Foundation. See README and COPYING for
296 * more details.
297 *
298 * Alternatively, this software may be distributed under the terms of BSD
299 * license.
300 */
301
302static void
303ccmp_init_blocks(rijndael_ctx *ctx, struct ieee80211_frame *wh,
304	u_int64_t pn, size_t dlen,
305	uint8_t b0[AES_BLOCK_LEN], uint8_t aad[2 * AES_BLOCK_LEN],
306	uint8_t auth[AES_BLOCK_LEN], uint8_t s0[AES_BLOCK_LEN])
307{
308#define	IS_QOS_DATA(wh)	IEEE80211_QOS_HAS_SEQ(wh)
309
310	/* CCM Initial Block:
311	 * Flag (Include authentication header, M=3 (8-octet MIC),
312	 *       L=1 (2-octet Dlen))
313	 * Nonce: 0x00 | A2 | PN
314	 * Dlen */
315	b0[0] = 0x59;
316	/* NB: b0[1] set below */
317	IEEE80211_ADDR_COPY(b0 + 2, wh->i_addr2);
318	b0[8] = pn >> 40;
319	b0[9] = pn >> 32;
320	b0[10] = pn >> 24;
321	b0[11] = pn >> 16;
322	b0[12] = pn >> 8;
323	b0[13] = pn >> 0;
324	b0[14] = (dlen >> 8) & 0xff;
325	b0[15] = dlen & 0xff;
326
327	/* AAD:
328	 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
329	 * A1 | A2 | A3
330	 * SC with bits 4..15 (seq#) masked to zero
331	 * A4 (if present)
332	 * QC (if present)
333	 */
334	aad[0] = 0;	/* AAD length >> 8 */
335	/* NB: aad[1] set below */
336	aad[2] = wh->i_fc[0] & 0x8f;	/* XXX magic #s */
337	aad[3] = wh->i_fc[1] & 0xc7;	/* XXX magic #s */
338	/* NB: we know 3 addresses are contiguous */
339	memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
340	aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
341	aad[23] = 0; /* all bits masked */
342	/*
343	 * Construct variable-length portion of AAD based
344	 * on whether this is a 4-address frame/QOS frame.
345	 * We always zero-pad to 32 bytes before running it
346	 * through the cipher.
347	 *
348	 * We also fill in the priority bits of the CCM
349	 * initial block as we know whether or not we have
350	 * a QOS frame.
351	 */
352	if (IEEE80211_IS_DSTODS(wh)) {
353		IEEE80211_ADDR_COPY(aad + 24,
354			((struct ieee80211_frame_addr4 *)wh)->i_addr4);
355		if (IS_QOS_DATA(wh)) {
356			struct ieee80211_qosframe_addr4 *qwh4 =
357				(struct ieee80211_qosframe_addr4 *) wh;
358			aad[30] = qwh4->i_qos[0] & 0x0f;/* just priority bits */
359			aad[31] = 0;
360			b0[1] = aad[30];
361			aad[1] = 22 + IEEE80211_ADDR_LEN + 2;
362		} else {
363			*(uint16_t *)&aad[30] = 0;
364			b0[1] = 0;
365			aad[1] = 22 + IEEE80211_ADDR_LEN;
366		}
367	} else {
368		if (IS_QOS_DATA(wh)) {
369			struct ieee80211_qosframe *qwh =
370				(struct ieee80211_qosframe*) wh;
371			aad[24] = qwh->i_qos[0] & 0x0f;	/* just priority bits */
372			aad[25] = 0;
373			b0[1] = aad[24];
374			aad[1] = 22 + 2;
375		} else {
376			*(uint16_t *)&aad[24] = 0;
377			b0[1] = 0;
378			aad[1] = 22;
379		}
380		*(uint16_t *)&aad[26] = 0;
381		*(uint32_t *)&aad[28] = 0;
382	}
383
384	/* Start with the first block and AAD */
385	rijndael_encrypt(ctx, b0, auth);
386	xor_block(auth, aad, AES_BLOCK_LEN);
387	rijndael_encrypt(ctx, auth, auth);
388	xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
389	rijndael_encrypt(ctx, auth, auth);
390	b0[0] &= 0x07;
391	b0[14] = b0[15] = 0;
392	rijndael_encrypt(ctx, b0, s0);
393#undef	IS_QOS_DATA
394}
395
396#define	CCMP_ENCRYPT(_i, _b, _b0, _pos, _e, _len) do {	\
397	/* Authentication */				\
398	xor_block(_b, _pos, _len);			\
399	rijndael_encrypt(&ctx->cc_aes, _b, _b);		\
400	/* Encryption, with counter */			\
401	_b0[14] = (_i >> 8) & 0xff;			\
402	_b0[15] = _i & 0xff;				\
403	rijndael_encrypt(&ctx->cc_aes, _b0, _e);	\
404	xor_block(_pos, _e, _len);			\
405} while (0)
406
407static int
408ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
409{
410	struct ccmp_ctx *ctx = key->wk_private;
411	struct ieee80211_frame *wh;
412	struct mbuf *m = m0;
413	int data_len, i, space;
414	uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN],
415		e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN];
416	uint8_t *pos;
417
418	ctx->cc_vap->iv_stats.is_crypto_ccmp++;
419
420	wh = mtod(m, struct ieee80211_frame *);
421	data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header);
422	ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc,
423		data_len, b0, aad, b, s0);
424
425	i = 1;
426	pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header;
427	/* NB: assumes header is entirely in first mbuf */
428	space = m->m_len - (hdrlen + ccmp.ic_header);
429	for (;;) {
430		if (space > data_len)
431			space = data_len;
432		/*
433		 * Do full blocks.
434		 */
435		while (space >= AES_BLOCK_LEN) {
436			CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN);
437			pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
438			data_len -= AES_BLOCK_LEN;
439			i++;
440		}
441		if (data_len <= 0)		/* no more data */
442			break;
443		m = m->m_next;
444		if (m == NULL) {		/* last buffer */
445			if (space != 0) {
446				/*
447				 * Short last block.
448				 */
449				CCMP_ENCRYPT(i, b, b0, pos, e, space);
450			}
451			break;
452		}
453		if (space != 0) {
454			uint8_t *pos_next;
455			int space_next;
456			int len, dl, sp;
457			struct mbuf *n;
458
459			/*
460			 * Block straddles one or more mbufs, gather data
461			 * into the block buffer b, apply the cipher, then
462			 * scatter the results back into the mbuf chain.
463			 * The buffer will automatically get space bytes
464			 * of data at offset 0 copied in+out by the
465			 * CCMP_ENCRYPT request so we must take care of
466			 * the remaining data.
467			 */
468			n = m;
469			dl = data_len;
470			sp = space;
471			for (;;) {
472				pos_next = mtod(n, uint8_t *);
473				len = min(dl, AES_BLOCK_LEN);
474				space_next = len > sp ? len - sp : 0;
475				if (n->m_len >= space_next) {
476					/*
477					 * This mbuf has enough data; just grab
478					 * what we need and stop.
479					 */
480					xor_block(b+sp, pos_next, space_next);
481					break;
482				}
483				/*
484				 * This mbuf's contents are insufficient,
485				 * take 'em all and prepare to advance to
486				 * the next mbuf.
487				 */
488				xor_block(b+sp, pos_next, n->m_len);
489				sp += n->m_len, dl -= n->m_len;
490				n = n->m_next;
491				if (n == NULL)
492					break;
493			}
494
495			CCMP_ENCRYPT(i, b, b0, pos, e, space);
496
497			/* NB: just like above, but scatter data to mbufs */
498			dl = data_len;
499			sp = space;
500			for (;;) {
501				pos_next = mtod(m, uint8_t *);
502				len = min(dl, AES_BLOCK_LEN);
503				space_next = len > sp ? len - sp : 0;
504				if (m->m_len >= space_next) {
505					xor_block(pos_next, e+sp, space_next);
506					break;
507				}
508				xor_block(pos_next, e+sp, m->m_len);
509				sp += m->m_len, dl -= m->m_len;
510				m = m->m_next;
511				if (m == NULL)
512					goto done;
513			}
514			/*
515			 * Do bookkeeping.  m now points to the last mbuf
516			 * we grabbed data from.  We know we consumed a
517			 * full block of data as otherwise we'd have hit
518			 * the end of the mbuf chain, so deduct from data_len.
519			 * Otherwise advance the block number (i) and setup
520			 * pos+space to reflect contents of the new mbuf.
521			 */
522			data_len -= AES_BLOCK_LEN;
523			i++;
524			pos = pos_next + space_next;
525			space = m->m_len - space_next;
526		} else {
527			/*
528			 * Setup for next buffer.
529			 */
530			pos = mtod(m, uint8_t *);
531			space = m->m_len;
532		}
533	}
534done:
535	/* tack on MIC */
536	xor_block(b, s0, ccmp.ic_trailer);
537	return m_append(m0, ccmp.ic_trailer, b);
538}
539#undef CCMP_ENCRYPT
540
541#define	CCMP_DECRYPT(_i, _b, _b0, _pos, _a, _len) do {	\
542	/* Decrypt, with counter */			\
543	_b0[14] = (_i >> 8) & 0xff;			\
544	_b0[15] = _i & 0xff;				\
545	rijndael_encrypt(&ctx->cc_aes, _b0, _b);	\
546	xor_block(_pos, _b, _len);			\
547	/* Authentication */				\
548	xor_block(_a, _pos, _len);			\
549	rijndael_encrypt(&ctx->cc_aes, _a, _a);		\
550} while (0)
551
552static int
553ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen)
554{
555	struct ccmp_ctx *ctx = key->wk_private;
556	struct ieee80211vap *vap = ctx->cc_vap;
557	struct ieee80211_frame *wh;
558	uint8_t aad[2 * AES_BLOCK_LEN];
559	uint8_t b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN];
560	uint8_t mic[AES_BLOCK_LEN];
561	size_t data_len;
562	int i;
563	uint8_t *pos;
564	u_int space;
565
566	ctx->cc_vap->iv_stats.is_crypto_ccmp++;
567
568	wh = mtod(m, struct ieee80211_frame *);
569	data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header + ccmp.ic_trailer);
570	ccmp_init_blocks(&ctx->cc_aes, wh, pn, data_len, b0, aad, a, b);
571	m_copydata(m, m->m_pkthdr.len - ccmp.ic_trailer, ccmp.ic_trailer, mic);
572	xor_block(mic, b, ccmp.ic_trailer);
573
574	i = 1;
575	pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header;
576	space = m->m_len - (hdrlen + ccmp.ic_header);
577	for (;;) {
578		if (space > data_len)
579			space = data_len;
580		while (space >= AES_BLOCK_LEN) {
581			CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN);
582			pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
583			data_len -= AES_BLOCK_LEN;
584			i++;
585		}
586		if (data_len <= 0)		/* no more data */
587			break;
588		m = m->m_next;
589		if (m == NULL) {		/* last buffer */
590			if (space != 0)		/* short last block */
591				CCMP_DECRYPT(i, b, b0, pos, a, space);
592			break;
593		}
594		if (space != 0) {
595			uint8_t *pos_next;
596			u_int space_next;
597			u_int len;
598
599			/*
600			 * Block straddles buffers, split references.  We
601			 * do not handle splits that require >2 buffers
602			 * since rx'd frames are never badly fragmented
603			 * because drivers typically recv in clusters.
604			 */
605			pos_next = mtod(m, uint8_t *);
606			len = min(data_len, AES_BLOCK_LEN);
607			space_next = len > space ? len - space : 0;
608			KASSERT(m->m_len >= space_next,
609				("not enough data in following buffer, "
610				"m_len %u need %u\n", m->m_len, space_next));
611
612			xor_block(b+space, pos_next, space_next);
613			CCMP_DECRYPT(i, b, b0, pos, a, space);
614			xor_block(pos_next, b+space, space_next);
615			data_len -= len;
616			i++;
617
618			pos = pos_next + space_next;
619			space = m->m_len - space_next;
620		} else {
621			/*
622			 * Setup for next buffer.
623			 */
624			pos = mtod(m, uint8_t *);
625			space = m->m_len;
626		}
627	}
628	if (memcmp(mic, a, ccmp.ic_trailer) != 0) {
629		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
630		    "%s", "AES-CCM decrypt failed; MIC mismatch");
631		vap->iv_stats.is_rx_ccmpmic++;
632		return 0;
633	}
634	return 1;
635}
636#undef CCMP_DECRYPT
637
638/*
639 * Module glue.
640 */
641IEEE80211_CRYPTO_MODULE(ccmp, 1);
642