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