132176cfdSRui Paulo /*-
232176cfdSRui Paulo * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3841ab66cSSepherosa Ziehau * All rights reserved.
4841ab66cSSepherosa Ziehau *
5841ab66cSSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
6841ab66cSSepherosa Ziehau * modification, are permitted provided that the following conditions
7841ab66cSSepherosa Ziehau * are met:
8841ab66cSSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
9841ab66cSSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
10841ab66cSSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
11841ab66cSSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the
12841ab66cSSepherosa Ziehau * documentation and/or other materials provided with the distribution.
13841ab66cSSepherosa Ziehau *
14841ab66cSSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15841ab66cSSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16841ab66cSSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17841ab66cSSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18841ab66cSSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19841ab66cSSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20841ab66cSSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21841ab66cSSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22841ab66cSSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23841ab66cSSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24841ab66cSSepherosa Ziehau */
25841ab66cSSepherosa Ziehau
26085ff963SMatthew Dillon #include <sys/cdefs.h>
27085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
28085ff963SMatthew Dillon
29841ab66cSSepherosa Ziehau /*
30841ab66cSSepherosa Ziehau * IEEE 802.11i AES-CCMP crypto support.
31841ab66cSSepherosa Ziehau *
32841ab66cSSepherosa Ziehau * Part of this module is derived from similar code in the Host
33841ab66cSSepherosa Ziehau * AP driver. The code is used with the consent of the author and
34841ab66cSSepherosa Ziehau * it's license is included below.
35841ab66cSSepherosa Ziehau */
3632176cfdSRui Paulo #include "opt_wlan.h"
3732176cfdSRui Paulo
38841ab66cSSepherosa Ziehau #include <sys/param.h>
39841ab66cSSepherosa Ziehau #include <sys/systm.h>
40841ab66cSSepherosa Ziehau #include <sys/mbuf.h>
41841ab66cSSepherosa Ziehau #include <sys/malloc.h>
42841ab66cSSepherosa Ziehau #include <sys/kernel.h>
43841ab66cSSepherosa Ziehau #include <sys/module.h>
44841ab66cSSepherosa Ziehau
45841ab66cSSepherosa Ziehau #include <sys/socket.h>
46841ab66cSSepherosa Ziehau
47841ab66cSSepherosa Ziehau #include <net/if.h>
48*bff82488SAaron LI #include <net/if_var.h>
49841ab66cSSepherosa Ziehau #include <net/if_media.h>
50841ab66cSSepherosa Ziehau #include <net/ethernet.h>
51841ab66cSSepherosa Ziehau
52841ab66cSSepherosa Ziehau #include <netproto/802_11/ieee80211_var.h>
53841ab66cSSepherosa Ziehau
5442ee1e6bSSascha Wildner #include <crypto/rijndael/rijndael.h>
55841ab66cSSepherosa Ziehau
56841ab66cSSepherosa Ziehau #define AES_BLOCK_LEN 16
57841ab66cSSepherosa Ziehau
58841ab66cSSepherosa Ziehau struct ccmp_ctx {
5932176cfdSRui Paulo struct ieee80211vap *cc_vap; /* for diagnostics+statistics */
6032176cfdSRui Paulo struct ieee80211com *cc_ic;
61841ab66cSSepherosa Ziehau rijndael_ctx cc_aes;
62841ab66cSSepherosa Ziehau };
63841ab66cSSepherosa Ziehau
6432176cfdSRui Paulo static void *ccmp_attach(struct ieee80211vap *, struct ieee80211_key *);
65841ab66cSSepherosa Ziehau static void ccmp_detach(struct ieee80211_key *);
66841ab66cSSepherosa Ziehau static int ccmp_setkey(struct ieee80211_key *);
674f655ef5SMatthew Dillon static void ccmp_setiv(struct ieee80211_key *, uint8_t *);
684f655ef5SMatthew Dillon static int ccmp_encap(struct ieee80211_key *, struct mbuf *);
69841ab66cSSepherosa Ziehau static int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
70841ab66cSSepherosa Ziehau static int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
71841ab66cSSepherosa Ziehau static int ccmp_demic(struct ieee80211_key *, struct mbuf *, int);
72841ab66cSSepherosa Ziehau
73841ab66cSSepherosa Ziehau static const struct ieee80211_cipher ccmp = {
74841ab66cSSepherosa Ziehau .ic_name = "AES-CCM",
75841ab66cSSepherosa Ziehau .ic_cipher = IEEE80211_CIPHER_AES_CCM,
76841ab66cSSepherosa Ziehau .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
77841ab66cSSepherosa Ziehau IEEE80211_WEP_EXTIVLEN,
78841ab66cSSepherosa Ziehau .ic_trailer = IEEE80211_WEP_MICLEN,
79841ab66cSSepherosa Ziehau .ic_miclen = 0,
80841ab66cSSepherosa Ziehau .ic_attach = ccmp_attach,
81841ab66cSSepherosa Ziehau .ic_detach = ccmp_detach,
82841ab66cSSepherosa Ziehau .ic_setkey = ccmp_setkey,
834f655ef5SMatthew Dillon .ic_setiv = ccmp_setiv,
84841ab66cSSepherosa Ziehau .ic_encap = ccmp_encap,
85841ab66cSSepherosa Ziehau .ic_decap = ccmp_decap,
86841ab66cSSepherosa Ziehau .ic_enmic = ccmp_enmic,
87841ab66cSSepherosa Ziehau .ic_demic = ccmp_demic,
88841ab66cSSepherosa Ziehau };
89841ab66cSSepherosa Ziehau
90841ab66cSSepherosa Ziehau static int ccmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
9132176cfdSRui Paulo static int ccmp_decrypt(struct ieee80211_key *, u_int64_t pn,
92841ab66cSSepherosa Ziehau struct mbuf *, int hdrlen);
93841ab66cSSepherosa Ziehau
94841ab66cSSepherosa Ziehau /* number of references from net80211 layer */
95841ab66cSSepherosa Ziehau static int nrefs = 0;
96841ab66cSSepherosa Ziehau
97841ab66cSSepherosa Ziehau static void *
ccmp_attach(struct ieee80211vap * vap,struct ieee80211_key * k)9832176cfdSRui Paulo ccmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
99841ab66cSSepherosa Ziehau {
100841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx;
101841ab66cSSepherosa Ziehau
1024f655ef5SMatthew Dillon #if defined(__DragonFly__)
10332176cfdSRui Paulo ctx = (struct ccmp_ctx *) kmalloc(sizeof(struct ccmp_ctx),
104c567b546SJoe Talbott M_80211_CRYPTO, M_INTWAIT | M_ZERO);
1054f655ef5SMatthew Dillon #else
1064f655ef5SMatthew Dillon ctx = (struct ccmp_ctx *) IEEE80211_MALLOC(sizeof(struct ccmp_ctx),
1074f655ef5SMatthew Dillon M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1084f655ef5SMatthew Dillon #endif
109841ab66cSSepherosa Ziehau if (ctx == NULL) {
11032176cfdSRui Paulo vap->iv_stats.is_crypto_nomem++;
111841ab66cSSepherosa Ziehau return NULL;
112841ab66cSSepherosa Ziehau }
11332176cfdSRui Paulo ctx->cc_vap = vap;
11432176cfdSRui Paulo ctx->cc_ic = vap->iv_ic;
115841ab66cSSepherosa Ziehau nrefs++; /* NB: we assume caller locking */
116841ab66cSSepherosa Ziehau return ctx;
117841ab66cSSepherosa Ziehau }
118841ab66cSSepherosa Ziehau
119841ab66cSSepherosa Ziehau static void
ccmp_detach(struct ieee80211_key * k)120841ab66cSSepherosa Ziehau ccmp_detach(struct ieee80211_key *k)
121841ab66cSSepherosa Ziehau {
122841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx = k->wk_private;
123841ab66cSSepherosa Ziehau
1244f655ef5SMatthew Dillon IEEE80211_FREE(ctx, M_80211_CRYPTO);
125841ab66cSSepherosa Ziehau KASSERT(nrefs > 0, ("imbalanced attach/detach"));
126841ab66cSSepherosa Ziehau nrefs--; /* NB: we assume caller locking */
127841ab66cSSepherosa Ziehau }
128841ab66cSSepherosa Ziehau
129841ab66cSSepherosa Ziehau static int
ccmp_setkey(struct ieee80211_key * k)130841ab66cSSepherosa Ziehau ccmp_setkey(struct ieee80211_key *k)
131841ab66cSSepherosa Ziehau {
132841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx = k->wk_private;
133841ab66cSSepherosa Ziehau
134841ab66cSSepherosa Ziehau if (k->wk_keylen != (128/NBBY)) {
13532176cfdSRui Paulo IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
136841ab66cSSepherosa Ziehau "%s: Invalid key length %u, expecting %u\n",
137841ab66cSSepherosa Ziehau __func__, k->wk_keylen, 128/NBBY);
138841ab66cSSepherosa Ziehau return 0;
139841ab66cSSepherosa Ziehau }
14032176cfdSRui Paulo if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)
14142ee1e6bSSascha Wildner rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);
142841ab66cSSepherosa Ziehau return 1;
143841ab66cSSepherosa Ziehau }
144841ab66cSSepherosa Ziehau
1454f655ef5SMatthew Dillon static void
ccmp_setiv(struct ieee80211_key * k,uint8_t * ivp)1464f655ef5SMatthew Dillon ccmp_setiv(struct ieee80211_key *k, uint8_t *ivp)
1474f655ef5SMatthew Dillon {
1484f655ef5SMatthew Dillon struct ccmp_ctx *ctx = k->wk_private;
1494f655ef5SMatthew Dillon struct ieee80211vap *vap = ctx->cc_vap;
1504f655ef5SMatthew Dillon uint8_t keyid;
1514f655ef5SMatthew Dillon
1524f655ef5SMatthew Dillon keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
1534f655ef5SMatthew Dillon
1544f655ef5SMatthew Dillon k->wk_keytsc++;
1554f655ef5SMatthew Dillon ivp[0] = k->wk_keytsc >> 0; /* PN0 */
1564f655ef5SMatthew Dillon ivp[1] = k->wk_keytsc >> 8; /* PN1 */
1574f655ef5SMatthew Dillon ivp[2] = 0; /* Reserved */
1584f655ef5SMatthew Dillon ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */
1594f655ef5SMatthew Dillon ivp[4] = k->wk_keytsc >> 16; /* PN2 */
1604f655ef5SMatthew Dillon ivp[5] = k->wk_keytsc >> 24; /* PN3 */
1614f655ef5SMatthew Dillon ivp[6] = k->wk_keytsc >> 32; /* PN4 */
1624f655ef5SMatthew Dillon ivp[7] = k->wk_keytsc >> 40; /* PN5 */
1634f655ef5SMatthew Dillon }
1644f655ef5SMatthew Dillon
165841ab66cSSepherosa Ziehau /*
166841ab66cSSepherosa Ziehau * Add privacy headers appropriate for the specified key.
167841ab66cSSepherosa Ziehau */
168841ab66cSSepherosa Ziehau static int
ccmp_encap(struct ieee80211_key * k,struct mbuf * m)1694f655ef5SMatthew Dillon ccmp_encap(struct ieee80211_key *k, struct mbuf *m)
170841ab66cSSepherosa Ziehau {
171841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx = k->wk_private;
172841ab66cSSepherosa Ziehau struct ieee80211com *ic = ctx->cc_ic;
173841ab66cSSepherosa Ziehau uint8_t *ivp;
174841ab66cSSepherosa Ziehau int hdrlen;
175841ab66cSSepherosa Ziehau
176841ab66cSSepherosa Ziehau hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
177841ab66cSSepherosa Ziehau
178841ab66cSSepherosa Ziehau /*
179841ab66cSSepherosa Ziehau * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
180841ab66cSSepherosa Ziehau */
181b5523eacSSascha Wildner M_PREPEND(m, ccmp.ic_header, M_NOWAIT);
182841ab66cSSepherosa Ziehau if (m == NULL)
183841ab66cSSepherosa Ziehau return 0;
184841ab66cSSepherosa Ziehau ivp = mtod(m, uint8_t *);
185afd2da4dSMatthew Dillon bcopy(ivp + ccmp.ic_header, ivp, hdrlen);
186841ab66cSSepherosa Ziehau ivp += hdrlen;
187841ab66cSSepherosa Ziehau
1884f655ef5SMatthew Dillon ccmp_setiv(k, ivp);
189841ab66cSSepherosa Ziehau
190841ab66cSSepherosa Ziehau /*
1914f655ef5SMatthew Dillon * Finally, do software encrypt if needed.
192841ab66cSSepherosa Ziehau */
19332176cfdSRui Paulo if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
194841ab66cSSepherosa Ziehau !ccmp_encrypt(k, m, hdrlen))
195841ab66cSSepherosa Ziehau return 0;
196841ab66cSSepherosa Ziehau
197841ab66cSSepherosa Ziehau return 1;
198841ab66cSSepherosa Ziehau }
199841ab66cSSepherosa Ziehau
200841ab66cSSepherosa Ziehau /*
201841ab66cSSepherosa Ziehau * Add MIC to the frame as needed.
202841ab66cSSepherosa Ziehau */
203841ab66cSSepherosa Ziehau static int
ccmp_enmic(struct ieee80211_key * k,struct mbuf * m,int force)204841ab66cSSepherosa Ziehau ccmp_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
205841ab66cSSepherosa Ziehau {
20632176cfdSRui Paulo
207841ab66cSSepherosa Ziehau return 1;
208841ab66cSSepherosa Ziehau }
209841ab66cSSepherosa Ziehau
210841ab66cSSepherosa Ziehau static __inline uint64_t
READ_6(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint8_t b5)211841ab66cSSepherosa Ziehau READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
212841ab66cSSepherosa Ziehau {
213841ab66cSSepherosa Ziehau uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
214841ab66cSSepherosa Ziehau uint16_t iv16 = (b4 << 0) | (b5 << 8);
215841ab66cSSepherosa Ziehau return (((uint64_t)iv16) << 32) | iv32;
216841ab66cSSepherosa Ziehau }
217841ab66cSSepherosa Ziehau
218841ab66cSSepherosa Ziehau /*
219841ab66cSSepherosa Ziehau * Validate and strip privacy headers (and trailer) for a
220841ab66cSSepherosa Ziehau * received frame. The specified key should be correct but
221841ab66cSSepherosa Ziehau * is also verified.
222841ab66cSSepherosa Ziehau */
223841ab66cSSepherosa Ziehau static int
ccmp_decap(struct ieee80211_key * k,struct mbuf * m,int hdrlen)224841ab66cSSepherosa Ziehau ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
225841ab66cSSepherosa Ziehau {
226841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx = k->wk_private;
22732176cfdSRui Paulo struct ieee80211vap *vap = ctx->cc_vap;
228841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
22932176cfdSRui Paulo uint8_t *ivp, tid;
230841ab66cSSepherosa Ziehau uint64_t pn;
231841ab66cSSepherosa Ziehau
232841ab66cSSepherosa Ziehau /*
233841ab66cSSepherosa Ziehau * Header should have extended IV and sequence number;
234841ab66cSSepherosa Ziehau * verify the former and validate the latter.
235841ab66cSSepherosa Ziehau */
236841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
237841ab66cSSepherosa Ziehau ivp = mtod(m, uint8_t *) + hdrlen;
238841ab66cSSepherosa Ziehau if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
239841ab66cSSepherosa Ziehau /*
240841ab66cSSepherosa Ziehau * No extended IV; discard frame.
241841ab66cSSepherosa Ziehau */
24232176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
24332176cfdSRui Paulo "%s", "missing ExtIV for AES-CCM cipher");
24432176cfdSRui Paulo vap->iv_stats.is_rx_ccmpformat++;
245841ab66cSSepherosa Ziehau return 0;
246841ab66cSSepherosa Ziehau }
24732176cfdSRui Paulo tid = ieee80211_gettid(wh);
248841ab66cSSepherosa Ziehau pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
249085ff963SMatthew Dillon if (pn <= k->wk_keyrsc[tid] &&
250085ff963SMatthew Dillon (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
251841ab66cSSepherosa Ziehau /*
252841ab66cSSepherosa Ziehau * Replay violation.
253841ab66cSSepherosa Ziehau */
25432176cfdSRui Paulo ieee80211_notify_replay_failure(vap, wh, k, pn, tid);
25532176cfdSRui Paulo vap->iv_stats.is_rx_ccmpreplay++;
256841ab66cSSepherosa Ziehau return 0;
257841ab66cSSepherosa Ziehau }
258841ab66cSSepherosa Ziehau
259841ab66cSSepherosa Ziehau /*
260841ab66cSSepherosa Ziehau * Check if the device handled the decrypt in hardware.
261841ab66cSSepherosa Ziehau * If so we just strip the header; otherwise we need to
262841ab66cSSepherosa Ziehau * handle the decrypt in software. Note that for the
263841ab66cSSepherosa Ziehau * latter we leave the header in place for use in the
264841ab66cSSepherosa Ziehau * decryption work.
265841ab66cSSepherosa Ziehau */
26632176cfdSRui Paulo if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
267841ab66cSSepherosa Ziehau !ccmp_decrypt(k, pn, m, hdrlen))
268841ab66cSSepherosa Ziehau return 0;
269841ab66cSSepherosa Ziehau
270841ab66cSSepherosa Ziehau /*
271841ab66cSSepherosa Ziehau * Copy up 802.11 header and strip crypto bits.
272841ab66cSSepherosa Ziehau */
273afd2da4dSMatthew Dillon bcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, hdrlen);
274841ab66cSSepherosa Ziehau m_adj(m, ccmp.ic_header);
275841ab66cSSepherosa Ziehau m_adj(m, -ccmp.ic_trailer);
276841ab66cSSepherosa Ziehau
277841ab66cSSepherosa Ziehau /*
278841ab66cSSepherosa Ziehau * Ok to update rsc now.
279841ab66cSSepherosa Ziehau */
28032176cfdSRui Paulo k->wk_keyrsc[tid] = pn;
281841ab66cSSepherosa Ziehau
282841ab66cSSepherosa Ziehau return 1;
283841ab66cSSepherosa Ziehau }
284841ab66cSSepherosa Ziehau
285841ab66cSSepherosa Ziehau /*
286841ab66cSSepherosa Ziehau * Verify and strip MIC from the frame.
287841ab66cSSepherosa Ziehau */
288841ab66cSSepherosa Ziehau static int
ccmp_demic(struct ieee80211_key * k,struct mbuf * m,int force)289841ab66cSSepherosa Ziehau ccmp_demic(struct ieee80211_key *k, struct mbuf *m, int force)
290841ab66cSSepherosa Ziehau {
291841ab66cSSepherosa Ziehau return 1;
292841ab66cSSepherosa Ziehau }
293841ab66cSSepherosa Ziehau
294841ab66cSSepherosa Ziehau static __inline void
xor_block(uint8_t * b,const uint8_t * a,size_t len)295841ab66cSSepherosa Ziehau xor_block(uint8_t *b, const uint8_t *a, size_t len)
296841ab66cSSepherosa Ziehau {
297841ab66cSSepherosa Ziehau int i;
298841ab66cSSepherosa Ziehau for (i = 0; i < len; i++)
299841ab66cSSepherosa Ziehau b[i] ^= a[i];
300841ab66cSSepherosa Ziehau }
301841ab66cSSepherosa Ziehau
302841ab66cSSepherosa Ziehau /*
303841ab66cSSepherosa Ziehau * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
304841ab66cSSepherosa Ziehau *
305841ab66cSSepherosa Ziehau * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
306841ab66cSSepherosa Ziehau *
307841ab66cSSepherosa Ziehau * This program is free software; you can redistribute it and/or modify
308841ab66cSSepherosa Ziehau * it under the terms of the GNU General Public License version 2 as
309841ab66cSSepherosa Ziehau * published by the Free Software Foundation. See README and COPYING for
310841ab66cSSepherosa Ziehau * more details.
311841ab66cSSepherosa Ziehau *
312841ab66cSSepherosa Ziehau * Alternatively, this software may be distributed under the terms of BSD
313841ab66cSSepherosa Ziehau * license.
314841ab66cSSepherosa Ziehau */
315841ab66cSSepherosa Ziehau
316841ab66cSSepherosa Ziehau static void
ccmp_init_blocks(rijndael_ctx * ctx,struct ieee80211_frame * wh,u_int64_t pn,size_t dlen,uint8_t b0[AES_BLOCK_LEN],uint8_t aad[2* AES_BLOCK_LEN],uint8_t auth[AES_BLOCK_LEN],uint8_t s0[AES_BLOCK_LEN])317841ab66cSSepherosa Ziehau ccmp_init_blocks(rijndael_ctx *ctx, struct ieee80211_frame *wh,
31832176cfdSRui Paulo u_int64_t pn, size_t dlen,
319841ab66cSSepherosa Ziehau uint8_t b0[AES_BLOCK_LEN], uint8_t aad[2 * AES_BLOCK_LEN],
320841ab66cSSepherosa Ziehau uint8_t auth[AES_BLOCK_LEN], uint8_t s0[AES_BLOCK_LEN])
321841ab66cSSepherosa Ziehau {
322841ab66cSSepherosa Ziehau #define IS_QOS_DATA(wh) IEEE80211_QOS_HAS_SEQ(wh)
323841ab66cSSepherosa Ziehau
324841ab66cSSepherosa Ziehau /* CCM Initial Block:
325841ab66cSSepherosa Ziehau * Flag (Include authentication header, M=3 (8-octet MIC),
326841ab66cSSepherosa Ziehau * L=1 (2-octet Dlen))
327841ab66cSSepherosa Ziehau * Nonce: 0x00 | A2 | PN
328841ab66cSSepherosa Ziehau * Dlen */
329841ab66cSSepherosa Ziehau b0[0] = 0x59;
330841ab66cSSepherosa Ziehau /* NB: b0[1] set below */
331841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(b0 + 2, wh->i_addr2);
332841ab66cSSepherosa Ziehau b0[8] = pn >> 40;
333841ab66cSSepherosa Ziehau b0[9] = pn >> 32;
334841ab66cSSepherosa Ziehau b0[10] = pn >> 24;
335841ab66cSSepherosa Ziehau b0[11] = pn >> 16;
336841ab66cSSepherosa Ziehau b0[12] = pn >> 8;
337841ab66cSSepherosa Ziehau b0[13] = pn >> 0;
338841ab66cSSepherosa Ziehau b0[14] = (dlen >> 8) & 0xff;
339841ab66cSSepherosa Ziehau b0[15] = dlen & 0xff;
340841ab66cSSepherosa Ziehau
341841ab66cSSepherosa Ziehau /* AAD:
342841ab66cSSepherosa Ziehau * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
343841ab66cSSepherosa Ziehau * A1 | A2 | A3
344841ab66cSSepherosa Ziehau * SC with bits 4..15 (seq#) masked to zero
345841ab66cSSepherosa Ziehau * A4 (if present)
346841ab66cSSepherosa Ziehau * QC (if present)
347841ab66cSSepherosa Ziehau */
348841ab66cSSepherosa Ziehau aad[0] = 0; /* AAD length >> 8 */
349841ab66cSSepherosa Ziehau /* NB: aad[1] set below */
350841ab66cSSepherosa Ziehau aad[2] = wh->i_fc[0] & 0x8f; /* XXX magic #s */
351841ab66cSSepherosa Ziehau aad[3] = wh->i_fc[1] & 0xc7; /* XXX magic #s */
352841ab66cSSepherosa Ziehau /* NB: we know 3 addresses are contiguous */
353841ab66cSSepherosa Ziehau memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
354841ab66cSSepherosa Ziehau aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
355841ab66cSSepherosa Ziehau aad[23] = 0; /* all bits masked */
356841ab66cSSepherosa Ziehau /*
357841ab66cSSepherosa Ziehau * Construct variable-length portion of AAD based
358841ab66cSSepherosa Ziehau * on whether this is a 4-address frame/QOS frame.
359841ab66cSSepherosa Ziehau * We always zero-pad to 32 bytes before running it
360841ab66cSSepherosa Ziehau * through the cipher.
361841ab66cSSepherosa Ziehau *
362841ab66cSSepherosa Ziehau * We also fill in the priority bits of the CCM
363841ab66cSSepherosa Ziehau * initial block as we know whether or not we have
364841ab66cSSepherosa Ziehau * a QOS frame.
365841ab66cSSepherosa Ziehau */
36632176cfdSRui Paulo if (IEEE80211_IS_DSTODS(wh)) {
367841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(aad + 24,
368841ab66cSSepherosa Ziehau ((struct ieee80211_frame_addr4 *)wh)->i_addr4);
369841ab66cSSepherosa Ziehau if (IS_QOS_DATA(wh)) {
370841ab66cSSepherosa Ziehau struct ieee80211_qosframe_addr4 *qwh4 =
371841ab66cSSepherosa Ziehau (struct ieee80211_qosframe_addr4 *) wh;
372841ab66cSSepherosa Ziehau aad[30] = qwh4->i_qos[0] & 0x0f;/* just priority bits */
373841ab66cSSepherosa Ziehau aad[31] = 0;
374841ab66cSSepherosa Ziehau b0[1] = aad[30];
375841ab66cSSepherosa Ziehau aad[1] = 22 + IEEE80211_ADDR_LEN + 2;
376841ab66cSSepherosa Ziehau } else {
377841ab66cSSepherosa Ziehau *(uint16_t *)&aad[30] = 0;
378841ab66cSSepherosa Ziehau b0[1] = 0;
379841ab66cSSepherosa Ziehau aad[1] = 22 + IEEE80211_ADDR_LEN;
380841ab66cSSepherosa Ziehau }
381841ab66cSSepherosa Ziehau } else {
382841ab66cSSepherosa Ziehau if (IS_QOS_DATA(wh)) {
383841ab66cSSepherosa Ziehau struct ieee80211_qosframe *qwh =
384841ab66cSSepherosa Ziehau (struct ieee80211_qosframe*) wh;
385841ab66cSSepherosa Ziehau aad[24] = qwh->i_qos[0] & 0x0f; /* just priority bits */
386841ab66cSSepherosa Ziehau aad[25] = 0;
387841ab66cSSepherosa Ziehau b0[1] = aad[24];
388841ab66cSSepherosa Ziehau aad[1] = 22 + 2;
389841ab66cSSepherosa Ziehau } else {
390841ab66cSSepherosa Ziehau *(uint16_t *)&aad[24] = 0;
391841ab66cSSepherosa Ziehau b0[1] = 0;
392841ab66cSSepherosa Ziehau aad[1] = 22;
393841ab66cSSepherosa Ziehau }
394841ab66cSSepherosa Ziehau *(uint16_t *)&aad[26] = 0;
395841ab66cSSepherosa Ziehau *(uint32_t *)&aad[28] = 0;
396841ab66cSSepherosa Ziehau }
397841ab66cSSepherosa Ziehau
398841ab66cSSepherosa Ziehau /* Start with the first block and AAD */
399841ab66cSSepherosa Ziehau rijndael_encrypt(ctx, b0, auth);
400841ab66cSSepherosa Ziehau xor_block(auth, aad, AES_BLOCK_LEN);
401841ab66cSSepherosa Ziehau rijndael_encrypt(ctx, auth, auth);
402841ab66cSSepherosa Ziehau xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
403841ab66cSSepherosa Ziehau rijndael_encrypt(ctx, auth, auth);
404841ab66cSSepherosa Ziehau b0[0] &= 0x07;
405841ab66cSSepherosa Ziehau b0[14] = b0[15] = 0;
406841ab66cSSepherosa Ziehau rijndael_encrypt(ctx, b0, s0);
407841ab66cSSepherosa Ziehau #undef IS_QOS_DATA
408841ab66cSSepherosa Ziehau }
409841ab66cSSepherosa Ziehau
410841ab66cSSepherosa Ziehau #define CCMP_ENCRYPT(_i, _b, _b0, _pos, _e, _len) do { \
411841ab66cSSepherosa Ziehau /* Authentication */ \
412841ab66cSSepherosa Ziehau xor_block(_b, _pos, _len); \
413841ab66cSSepherosa Ziehau rijndael_encrypt(&ctx->cc_aes, _b, _b); \
414841ab66cSSepherosa Ziehau /* Encryption, with counter */ \
415841ab66cSSepherosa Ziehau _b0[14] = (_i >> 8) & 0xff; \
416841ab66cSSepherosa Ziehau _b0[15] = _i & 0xff; \
417841ab66cSSepherosa Ziehau rijndael_encrypt(&ctx->cc_aes, _b0, _e); \
418841ab66cSSepherosa Ziehau xor_block(_pos, _e, _len); \
419841ab66cSSepherosa Ziehau } while (0)
420841ab66cSSepherosa Ziehau
421841ab66cSSepherosa Ziehau static int
ccmp_encrypt(struct ieee80211_key * key,struct mbuf * m0,int hdrlen)422841ab66cSSepherosa Ziehau ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
423841ab66cSSepherosa Ziehau {
424841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx = key->wk_private;
425841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
426841ab66cSSepherosa Ziehau struct mbuf *m = m0;
427841ab66cSSepherosa Ziehau int data_len, i, space;
428841ab66cSSepherosa Ziehau uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN],
429841ab66cSSepherosa Ziehau e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN];
430841ab66cSSepherosa Ziehau uint8_t *pos;
431841ab66cSSepherosa Ziehau
43232176cfdSRui Paulo ctx->cc_vap->iv_stats.is_crypto_ccmp++;
433841ab66cSSepherosa Ziehau
434841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
435841ab66cSSepherosa Ziehau data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header);
436841ab66cSSepherosa Ziehau ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc,
437841ab66cSSepherosa Ziehau data_len, b0, aad, b, s0);
438841ab66cSSepherosa Ziehau
439841ab66cSSepherosa Ziehau i = 1;
440841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header;
441841ab66cSSepherosa Ziehau /* NB: assumes header is entirely in first mbuf */
442841ab66cSSepherosa Ziehau space = m->m_len - (hdrlen + ccmp.ic_header);
443841ab66cSSepherosa Ziehau for (;;) {
444841ab66cSSepherosa Ziehau if (space > data_len)
445841ab66cSSepherosa Ziehau space = data_len;
446841ab66cSSepherosa Ziehau /*
447841ab66cSSepherosa Ziehau * Do full blocks.
448841ab66cSSepherosa Ziehau */
449841ab66cSSepherosa Ziehau while (space >= AES_BLOCK_LEN) {
450841ab66cSSepherosa Ziehau CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN);
451841ab66cSSepherosa Ziehau pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
452841ab66cSSepherosa Ziehau data_len -= AES_BLOCK_LEN;
453841ab66cSSepherosa Ziehau i++;
454841ab66cSSepherosa Ziehau }
455841ab66cSSepherosa Ziehau if (data_len <= 0) /* no more data */
456841ab66cSSepherosa Ziehau break;
457841ab66cSSepherosa Ziehau m = m->m_next;
458841ab66cSSepherosa Ziehau if (m == NULL) { /* last buffer */
459841ab66cSSepherosa Ziehau if (space != 0) {
460841ab66cSSepherosa Ziehau /*
461841ab66cSSepherosa Ziehau * Short last block.
462841ab66cSSepherosa Ziehau */
463841ab66cSSepherosa Ziehau CCMP_ENCRYPT(i, b, b0, pos, e, space);
464841ab66cSSepherosa Ziehau }
465841ab66cSSepherosa Ziehau break;
466841ab66cSSepherosa Ziehau }
467841ab66cSSepherosa Ziehau if (space != 0) {
468841ab66cSSepherosa Ziehau uint8_t *pos_next;
469841ab66cSSepherosa Ziehau int space_next;
470841ab66cSSepherosa Ziehau int len, dl, sp;
471841ab66cSSepherosa Ziehau struct mbuf *n;
472841ab66cSSepherosa Ziehau
473841ab66cSSepherosa Ziehau /*
474841ab66cSSepherosa Ziehau * Block straddles one or more mbufs, gather data
475841ab66cSSepherosa Ziehau * into the block buffer b, apply the cipher, then
476841ab66cSSepherosa Ziehau * scatter the results back into the mbuf chain.
477841ab66cSSepherosa Ziehau * The buffer will automatically get space bytes
478841ab66cSSepherosa Ziehau * of data at offset 0 copied in+out by the
479841ab66cSSepherosa Ziehau * CCMP_ENCRYPT request so we must take care of
480841ab66cSSepherosa Ziehau * the remaining data.
481841ab66cSSepherosa Ziehau */
482841ab66cSSepherosa Ziehau n = m;
483841ab66cSSepherosa Ziehau dl = data_len;
484841ab66cSSepherosa Ziehau sp = space;
485841ab66cSSepherosa Ziehau for (;;) {
486841ab66cSSepherosa Ziehau pos_next = mtod(n, uint8_t *);
487841ab66cSSepherosa Ziehau len = min(dl, AES_BLOCK_LEN);
488841ab66cSSepherosa Ziehau space_next = len > sp ? len - sp : 0;
489841ab66cSSepherosa Ziehau if (n->m_len >= space_next) {
490841ab66cSSepherosa Ziehau /*
491841ab66cSSepherosa Ziehau * This mbuf has enough data; just grab
492841ab66cSSepherosa Ziehau * what we need and stop.
493841ab66cSSepherosa Ziehau */
494841ab66cSSepherosa Ziehau xor_block(b+sp, pos_next, space_next);
495841ab66cSSepherosa Ziehau break;
496841ab66cSSepherosa Ziehau }
497841ab66cSSepherosa Ziehau /*
498841ab66cSSepherosa Ziehau * This mbuf's contents are insufficient,
499841ab66cSSepherosa Ziehau * take 'em all and prepare to advance to
500841ab66cSSepherosa Ziehau * the next mbuf.
501841ab66cSSepherosa Ziehau */
502841ab66cSSepherosa Ziehau xor_block(b+sp, pos_next, n->m_len);
503841ab66cSSepherosa Ziehau sp += n->m_len, dl -= n->m_len;
504841ab66cSSepherosa Ziehau n = n->m_next;
505841ab66cSSepherosa Ziehau if (n == NULL)
506841ab66cSSepherosa Ziehau break;
507841ab66cSSepherosa Ziehau }
508841ab66cSSepherosa Ziehau
509841ab66cSSepherosa Ziehau CCMP_ENCRYPT(i, b, b0, pos, e, space);
510841ab66cSSepherosa Ziehau
511841ab66cSSepherosa Ziehau /* NB: just like above, but scatter data to mbufs */
512841ab66cSSepherosa Ziehau dl = data_len;
513841ab66cSSepherosa Ziehau sp = space;
514841ab66cSSepherosa Ziehau for (;;) {
515841ab66cSSepherosa Ziehau pos_next = mtod(m, uint8_t *);
516841ab66cSSepherosa Ziehau len = min(dl, AES_BLOCK_LEN);
517841ab66cSSepherosa Ziehau space_next = len > sp ? len - sp : 0;
518841ab66cSSepherosa Ziehau if (m->m_len >= space_next) {
519841ab66cSSepherosa Ziehau xor_block(pos_next, e+sp, space_next);
520841ab66cSSepherosa Ziehau break;
521841ab66cSSepherosa Ziehau }
522841ab66cSSepherosa Ziehau xor_block(pos_next, e+sp, m->m_len);
523841ab66cSSepherosa Ziehau sp += m->m_len, dl -= m->m_len;
524841ab66cSSepherosa Ziehau m = m->m_next;
525841ab66cSSepherosa Ziehau if (m == NULL)
526841ab66cSSepherosa Ziehau goto done;
527841ab66cSSepherosa Ziehau }
528841ab66cSSepherosa Ziehau /*
529841ab66cSSepherosa Ziehau * Do bookkeeping. m now points to the last mbuf
530841ab66cSSepherosa Ziehau * we grabbed data from. We know we consumed a
531841ab66cSSepherosa Ziehau * full block of data as otherwise we'd have hit
532841ab66cSSepherosa Ziehau * the end of the mbuf chain, so deduct from data_len.
533841ab66cSSepherosa Ziehau * Otherwise advance the block number (i) and setup
534841ab66cSSepherosa Ziehau * pos+space to reflect contents of the new mbuf.
535841ab66cSSepherosa Ziehau */
536841ab66cSSepherosa Ziehau data_len -= AES_BLOCK_LEN;
537841ab66cSSepherosa Ziehau i++;
538841ab66cSSepherosa Ziehau pos = pos_next + space_next;
539841ab66cSSepherosa Ziehau space = m->m_len - space_next;
540841ab66cSSepherosa Ziehau } else {
541841ab66cSSepherosa Ziehau /*
542841ab66cSSepherosa Ziehau * Setup for next buffer.
543841ab66cSSepherosa Ziehau */
544841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *);
545841ab66cSSepherosa Ziehau space = m->m_len;
546841ab66cSSepherosa Ziehau }
547841ab66cSSepherosa Ziehau }
548841ab66cSSepherosa Ziehau done:
549841ab66cSSepherosa Ziehau /* tack on MIC */
550841ab66cSSepherosa Ziehau xor_block(b, s0, ccmp.ic_trailer);
55132176cfdSRui Paulo return m_append(m0, ccmp.ic_trailer, b);
552841ab66cSSepherosa Ziehau }
553841ab66cSSepherosa Ziehau #undef CCMP_ENCRYPT
554841ab66cSSepherosa Ziehau
555841ab66cSSepherosa Ziehau #define CCMP_DECRYPT(_i, _b, _b0, _pos, _a, _len) do { \
556841ab66cSSepherosa Ziehau /* Decrypt, with counter */ \
557841ab66cSSepherosa Ziehau _b0[14] = (_i >> 8) & 0xff; \
558841ab66cSSepherosa Ziehau _b0[15] = _i & 0xff; \
559841ab66cSSepherosa Ziehau rijndael_encrypt(&ctx->cc_aes, _b0, _b); \
560841ab66cSSepherosa Ziehau xor_block(_pos, _b, _len); \
561841ab66cSSepherosa Ziehau /* Authentication */ \
562841ab66cSSepherosa Ziehau xor_block(_a, _pos, _len); \
563841ab66cSSepherosa Ziehau rijndael_encrypt(&ctx->cc_aes, _a, _a); \
564841ab66cSSepherosa Ziehau } while (0)
565841ab66cSSepherosa Ziehau
566841ab66cSSepherosa Ziehau static int
ccmp_decrypt(struct ieee80211_key * key,u_int64_t pn,struct mbuf * m,int hdrlen)56732176cfdSRui Paulo ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen)
568841ab66cSSepherosa Ziehau {
569841ab66cSSepherosa Ziehau struct ccmp_ctx *ctx = key->wk_private;
57032176cfdSRui Paulo struct ieee80211vap *vap = ctx->cc_vap;
571841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
572841ab66cSSepherosa Ziehau uint8_t aad[2 * AES_BLOCK_LEN];
573841ab66cSSepherosa Ziehau uint8_t b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN];
574841ab66cSSepherosa Ziehau uint8_t mic[AES_BLOCK_LEN];
575841ab66cSSepherosa Ziehau size_t data_len;
576841ab66cSSepherosa Ziehau int i;
577841ab66cSSepherosa Ziehau uint8_t *pos;
578841ab66cSSepherosa Ziehau u_int space;
579841ab66cSSepherosa Ziehau
58032176cfdSRui Paulo ctx->cc_vap->iv_stats.is_crypto_ccmp++;
581841ab66cSSepherosa Ziehau
582841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
58332176cfdSRui Paulo data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header + ccmp.ic_trailer);
584841ab66cSSepherosa Ziehau ccmp_init_blocks(&ctx->cc_aes, wh, pn, data_len, b0, aad, a, b);
58532176cfdSRui Paulo m_copydata(m, m->m_pkthdr.len - ccmp.ic_trailer, ccmp.ic_trailer, mic);
586841ab66cSSepherosa Ziehau xor_block(mic, b, ccmp.ic_trailer);
587841ab66cSSepherosa Ziehau
588841ab66cSSepherosa Ziehau i = 1;
589841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header;
590841ab66cSSepherosa Ziehau space = m->m_len - (hdrlen + ccmp.ic_header);
591841ab66cSSepherosa Ziehau for (;;) {
592841ab66cSSepherosa Ziehau if (space > data_len)
593841ab66cSSepherosa Ziehau space = data_len;
594841ab66cSSepherosa Ziehau while (space >= AES_BLOCK_LEN) {
595841ab66cSSepherosa Ziehau CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN);
596841ab66cSSepherosa Ziehau pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
597841ab66cSSepherosa Ziehau data_len -= AES_BLOCK_LEN;
598841ab66cSSepherosa Ziehau i++;
599841ab66cSSepherosa Ziehau }
600841ab66cSSepherosa Ziehau if (data_len <= 0) /* no more data */
601841ab66cSSepherosa Ziehau break;
602841ab66cSSepherosa Ziehau m = m->m_next;
603841ab66cSSepherosa Ziehau if (m == NULL) { /* last buffer */
604841ab66cSSepherosa Ziehau if (space != 0) /* short last block */
605841ab66cSSepherosa Ziehau CCMP_DECRYPT(i, b, b0, pos, a, space);
606841ab66cSSepherosa Ziehau break;
607841ab66cSSepherosa Ziehau }
608841ab66cSSepherosa Ziehau if (space != 0) {
609841ab66cSSepherosa Ziehau uint8_t *pos_next;
610841ab66cSSepherosa Ziehau u_int space_next;
611841ab66cSSepherosa Ziehau u_int len;
612841ab66cSSepherosa Ziehau
613841ab66cSSepherosa Ziehau /*
614841ab66cSSepherosa Ziehau * Block straddles buffers, split references. We
615841ab66cSSepherosa Ziehau * do not handle splits that require >2 buffers
616841ab66cSSepherosa Ziehau * since rx'd frames are never badly fragmented
617841ab66cSSepherosa Ziehau * because drivers typically recv in clusters.
618841ab66cSSepherosa Ziehau */
619841ab66cSSepherosa Ziehau pos_next = mtod(m, uint8_t *);
620841ab66cSSepherosa Ziehau len = min(data_len, AES_BLOCK_LEN);
621841ab66cSSepherosa Ziehau space_next = len > space ? len - space : 0;
622841ab66cSSepherosa Ziehau KASSERT(m->m_len >= space_next,
623841ab66cSSepherosa Ziehau ("not enough data in following buffer, "
624085ff963SMatthew Dillon "m_len %u need %u\n", m->m_len, space_next));
625841ab66cSSepherosa Ziehau
626841ab66cSSepherosa Ziehau xor_block(b+space, pos_next, space_next);
627841ab66cSSepherosa Ziehau CCMP_DECRYPT(i, b, b0, pos, a, space);
628841ab66cSSepherosa Ziehau xor_block(pos_next, b+space, space_next);
629841ab66cSSepherosa Ziehau data_len -= len;
630841ab66cSSepherosa Ziehau i++;
631841ab66cSSepherosa Ziehau
632841ab66cSSepherosa Ziehau pos = pos_next + space_next;
633841ab66cSSepherosa Ziehau space = m->m_len - space_next;
634841ab66cSSepherosa Ziehau } else {
635841ab66cSSepherosa Ziehau /*
636841ab66cSSepherosa Ziehau * Setup for next buffer.
637841ab66cSSepherosa Ziehau */
638841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *);
639841ab66cSSepherosa Ziehau space = m->m_len;
640841ab66cSSepherosa Ziehau }
641841ab66cSSepherosa Ziehau }
642841ab66cSSepherosa Ziehau if (memcmp(mic, a, ccmp.ic_trailer) != 0) {
64332176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
64432176cfdSRui Paulo "%s", "AES-CCM decrypt failed; MIC mismatch");
64532176cfdSRui Paulo vap->iv_stats.is_rx_ccmpmic++;
646841ab66cSSepherosa Ziehau return 0;
647841ab66cSSepherosa Ziehau }
648841ab66cSSepherosa Ziehau return 1;
649841ab66cSSepherosa Ziehau }
650841ab66cSSepherosa Ziehau #undef CCMP_DECRYPT
651841ab66cSSepherosa Ziehau
652841ab66cSSepherosa Ziehau /*
653841ab66cSSepherosa Ziehau * Module glue.
654841ab66cSSepherosa Ziehau */
65532176cfdSRui Paulo IEEE80211_CRYPTO_MODULE(ccmp, 1);
656