xref: /freebsd/sys/net80211/ieee80211_crypto_gcmp.c (revision 2d4583c462a5d7904e2bb4c77f521d16fd2e7140)
1*2d4583c4SAdrian Chadd /*-
2*2d4583c4SAdrian Chadd  * SPDX-License-Identifier: BSD-2-Clause
3*2d4583c4SAdrian Chadd  *
4*2d4583c4SAdrian Chadd  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
5*2d4583c4SAdrian Chadd  * All rights reserved.
6*2d4583c4SAdrian Chadd  * Copyright (c) 2025 Adrian Chadd <adrian@FreeBSD.org>.
7*2d4583c4SAdrian Chadd  *
8*2d4583c4SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
9*2d4583c4SAdrian Chadd  * modification, are permitted provided that the following conditions
10*2d4583c4SAdrian Chadd  * are met:
11*2d4583c4SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
12*2d4583c4SAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
13*2d4583c4SAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
14*2d4583c4SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
15*2d4583c4SAdrian Chadd  *    documentation and/or other materials provided with the distribution.
16*2d4583c4SAdrian Chadd  *
17*2d4583c4SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*2d4583c4SAdrian Chadd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*2d4583c4SAdrian Chadd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*2d4583c4SAdrian Chadd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*2d4583c4SAdrian Chadd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*2d4583c4SAdrian Chadd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*2d4583c4SAdrian Chadd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*2d4583c4SAdrian Chadd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*2d4583c4SAdrian Chadd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*2d4583c4SAdrian Chadd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*2d4583c4SAdrian Chadd  */
28*2d4583c4SAdrian Chadd 
29*2d4583c4SAdrian Chadd /*
30*2d4583c4SAdrian Chadd  * IEEE 802.11 AES-GCMP crypto support.
31*2d4583c4SAdrian Chadd  *
32*2d4583c4SAdrian Chadd  * The AES-GCM crypto routines in sys/net80211/ieee80211_crypto_gcm.[ch]
33*2d4583c4SAdrian Chadd  * are derived from similar code in hostapd 2.11 (src/crypto/aes-gcm.c).
34*2d4583c4SAdrian Chadd  * The code is used with the consent of the author and its licence is
35*2d4583c4SAdrian Chadd  * included in the above source files.
36*2d4583c4SAdrian Chadd  */
37*2d4583c4SAdrian Chadd #include "opt_wlan.h"
38*2d4583c4SAdrian Chadd 
39*2d4583c4SAdrian Chadd #include <sys/param.h>
40*2d4583c4SAdrian Chadd #include <sys/systm.h>
41*2d4583c4SAdrian Chadd #include <sys/mbuf.h>
42*2d4583c4SAdrian Chadd #include <sys/malloc.h>
43*2d4583c4SAdrian Chadd #include <sys/kernel.h>
44*2d4583c4SAdrian Chadd #include <sys/module.h>
45*2d4583c4SAdrian Chadd 
46*2d4583c4SAdrian Chadd #include <sys/socket.h>
47*2d4583c4SAdrian Chadd 
48*2d4583c4SAdrian Chadd #include <net/if.h>
49*2d4583c4SAdrian Chadd #include <net/if_media.h>
50*2d4583c4SAdrian Chadd #include <net/ethernet.h>
51*2d4583c4SAdrian Chadd 
52*2d4583c4SAdrian Chadd #include <net80211/ieee80211_var.h>
53*2d4583c4SAdrian Chadd #include <net80211/ieee80211_crypto_gcm.h>
54*2d4583c4SAdrian Chadd 
55*2d4583c4SAdrian Chadd #include <crypto/rijndael/rijndael.h>
56*2d4583c4SAdrian Chadd 
57*2d4583c4SAdrian Chadd #define AES_BLOCK_LEN 16
58*2d4583c4SAdrian Chadd 
59*2d4583c4SAdrian Chadd /*
60*2d4583c4SAdrian Chadd  * Note: GCMP_MIC_LEN defined in ieee80211_crypto_gcm.h, as it is also
61*2d4583c4SAdrian Chadd  * used by the AES-GCM routines for sizing the S and T hashes which are
62*2d4583c4SAdrian Chadd  * used by GCMP as the MIC.
63*2d4583c4SAdrian Chadd  */
64*2d4583c4SAdrian Chadd #define	GCMP_PN_LEN	6
65*2d4583c4SAdrian Chadd #define	GCMP_IV_LEN	12
66*2d4583c4SAdrian Chadd 
67*2d4583c4SAdrian Chadd struct gcmp_ctx {
68*2d4583c4SAdrian Chadd 	struct ieee80211vap *cc_vap;	/* for diagnostics+statistics */
69*2d4583c4SAdrian Chadd 	struct ieee80211com *cc_ic;
70*2d4583c4SAdrian Chadd 	rijndael_ctx	     cc_aes;
71*2d4583c4SAdrian Chadd };
72*2d4583c4SAdrian Chadd 
73*2d4583c4SAdrian Chadd static	void *gcmp_attach(struct ieee80211vap *, struct ieee80211_key *);
74*2d4583c4SAdrian Chadd static	void gcmp_detach(struct ieee80211_key *);
75*2d4583c4SAdrian Chadd static	int gcmp_setkey(struct ieee80211_key *);
76*2d4583c4SAdrian Chadd static	void gcmp_setiv(struct ieee80211_key *, uint8_t *);
77*2d4583c4SAdrian Chadd static	int gcmp_encap(struct ieee80211_key *, struct mbuf *);
78*2d4583c4SAdrian Chadd static	int gcmp_decap(struct ieee80211_key *, struct mbuf *, int);
79*2d4583c4SAdrian Chadd static	int gcmp_enmic(struct ieee80211_key *, struct mbuf *, int);
80*2d4583c4SAdrian Chadd static	int gcmp_demic(struct ieee80211_key *, struct mbuf *, int);
81*2d4583c4SAdrian Chadd 
82*2d4583c4SAdrian Chadd static const struct ieee80211_cipher gcmp = {
83*2d4583c4SAdrian Chadd 	.ic_name	= "AES-GCMP",
84*2d4583c4SAdrian Chadd 	.ic_cipher	= IEEE80211_CIPHER_AES_GCM_128,
85*2d4583c4SAdrian Chadd 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
86*2d4583c4SAdrian Chadd 			  IEEE80211_WEP_EXTIVLEN,
87*2d4583c4SAdrian Chadd 	.ic_trailer	= GCMP_MIC_LEN,
88*2d4583c4SAdrian Chadd 	.ic_miclen	= 0,
89*2d4583c4SAdrian Chadd 	.ic_attach	= gcmp_attach,
90*2d4583c4SAdrian Chadd 	.ic_detach	= gcmp_detach,
91*2d4583c4SAdrian Chadd 	.ic_setkey	= gcmp_setkey,
92*2d4583c4SAdrian Chadd 	.ic_setiv	= gcmp_setiv,
93*2d4583c4SAdrian Chadd 	.ic_encap	= gcmp_encap,
94*2d4583c4SAdrian Chadd 	.ic_decap	= gcmp_decap,
95*2d4583c4SAdrian Chadd 	.ic_enmic	= gcmp_enmic,
96*2d4583c4SAdrian Chadd 	.ic_demic	= gcmp_demic,
97*2d4583c4SAdrian Chadd };
98*2d4583c4SAdrian Chadd 
99*2d4583c4SAdrian Chadd static const struct ieee80211_cipher gcmp_256 = {
100*2d4583c4SAdrian Chadd 	.ic_name	= "AES-GCMP-256",
101*2d4583c4SAdrian Chadd 	.ic_cipher	= IEEE80211_CIPHER_AES_GCM_256,
102*2d4583c4SAdrian Chadd 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
103*2d4583c4SAdrian Chadd 			  IEEE80211_WEP_EXTIVLEN,
104*2d4583c4SAdrian Chadd 	.ic_trailer	= GCMP_MIC_LEN,
105*2d4583c4SAdrian Chadd 	.ic_miclen	= 0,
106*2d4583c4SAdrian Chadd 	.ic_attach	= gcmp_attach,
107*2d4583c4SAdrian Chadd 	.ic_detach	= gcmp_detach,
108*2d4583c4SAdrian Chadd 	.ic_setkey	= gcmp_setkey,
109*2d4583c4SAdrian Chadd 	.ic_setiv	= gcmp_setiv,
110*2d4583c4SAdrian Chadd 	.ic_encap	= gcmp_encap,
111*2d4583c4SAdrian Chadd 	.ic_decap	= gcmp_decap,
112*2d4583c4SAdrian Chadd 	.ic_enmic	= gcmp_enmic,
113*2d4583c4SAdrian Chadd 	.ic_demic	= gcmp_demic,
114*2d4583c4SAdrian Chadd };
115*2d4583c4SAdrian Chadd 
116*2d4583c4SAdrian Chadd 
117*2d4583c4SAdrian Chadd static	int gcmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
118*2d4583c4SAdrian Chadd static	int gcmp_decrypt(struct ieee80211_key *, u_int64_t pn,
119*2d4583c4SAdrian Chadd 		struct mbuf *, int hdrlen);
120*2d4583c4SAdrian Chadd 
121*2d4583c4SAdrian Chadd /* number of references from net80211 layer */
122*2d4583c4SAdrian Chadd static	int nrefs = 0;
123*2d4583c4SAdrian Chadd 
124*2d4583c4SAdrian Chadd static void *
125*2d4583c4SAdrian Chadd gcmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
126*2d4583c4SAdrian Chadd {
127*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx;
128*2d4583c4SAdrian Chadd 
129*2d4583c4SAdrian Chadd 	ctx = (struct gcmp_ctx *) IEEE80211_MALLOC(sizeof(struct gcmp_ctx),
130*2d4583c4SAdrian Chadd 		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
131*2d4583c4SAdrian Chadd 	if (ctx == NULL) {
132*2d4583c4SAdrian Chadd 		vap->iv_stats.is_crypto_nomem++;
133*2d4583c4SAdrian Chadd 		return (NULL);
134*2d4583c4SAdrian Chadd 	}
135*2d4583c4SAdrian Chadd 	ctx->cc_vap = vap;
136*2d4583c4SAdrian Chadd 	ctx->cc_ic = vap->iv_ic;
137*2d4583c4SAdrian Chadd 	nrefs++;			/* NB: we assume caller locking */
138*2d4583c4SAdrian Chadd 	return (ctx);
139*2d4583c4SAdrian Chadd }
140*2d4583c4SAdrian Chadd 
141*2d4583c4SAdrian Chadd static void
142*2d4583c4SAdrian Chadd gcmp_detach(struct ieee80211_key *k)
143*2d4583c4SAdrian Chadd {
144*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
145*2d4583c4SAdrian Chadd 
146*2d4583c4SAdrian Chadd 	IEEE80211_FREE(ctx, M_80211_CRYPTO);
147*2d4583c4SAdrian Chadd 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
148*2d4583c4SAdrian Chadd 	nrefs--;			/* NB: we assume caller locking */
149*2d4583c4SAdrian Chadd }
150*2d4583c4SAdrian Chadd 
151*2d4583c4SAdrian Chadd static int
152*2d4583c4SAdrian Chadd gcmp_get_trailer_len(struct ieee80211_key *k)
153*2d4583c4SAdrian Chadd {
154*2d4583c4SAdrian Chadd 	return (k->wk_cipher->ic_trailer);
155*2d4583c4SAdrian Chadd }
156*2d4583c4SAdrian Chadd 
157*2d4583c4SAdrian Chadd static int
158*2d4583c4SAdrian Chadd gcmp_get_header_len(struct ieee80211_key *k)
159*2d4583c4SAdrian Chadd {
160*2d4583c4SAdrian Chadd 	return (k->wk_cipher->ic_header);
161*2d4583c4SAdrian Chadd }
162*2d4583c4SAdrian Chadd 
163*2d4583c4SAdrian Chadd static int
164*2d4583c4SAdrian Chadd gcmp_setkey(struct ieee80211_key *k)
165*2d4583c4SAdrian Chadd {
166*2d4583c4SAdrian Chadd 	uint32_t keylen;
167*2d4583c4SAdrian Chadd 
168*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
169*2d4583c4SAdrian Chadd 
170*2d4583c4SAdrian Chadd 	switch (k->wk_cipher->ic_cipher) {
171*2d4583c4SAdrian Chadd 	case IEEE80211_CIPHER_AES_GCM_128:
172*2d4583c4SAdrian Chadd 		keylen = 128;
173*2d4583c4SAdrian Chadd 		break;
174*2d4583c4SAdrian Chadd 	case IEEE80211_CIPHER_AES_GCM_256:
175*2d4583c4SAdrian Chadd 		keylen = 256;
176*2d4583c4SAdrian Chadd 		break;
177*2d4583c4SAdrian Chadd 	default:
178*2d4583c4SAdrian Chadd 		IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
179*2d4583c4SAdrian Chadd 			"%s: Unexpected cipher (%u)",
180*2d4583c4SAdrian Chadd 			__func__, k->wk_cipher->ic_cipher);
181*2d4583c4SAdrian Chadd 		return (0);
182*2d4583c4SAdrian Chadd 	}
183*2d4583c4SAdrian Chadd 
184*2d4583c4SAdrian Chadd 	if (k->wk_keylen != (keylen/NBBY)) {
185*2d4583c4SAdrian Chadd 		IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
186*2d4583c4SAdrian Chadd 			"%s: Invalid key length %u, expecting %u\n",
187*2d4583c4SAdrian Chadd 			__func__, k->wk_keylen, keylen/NBBY);
188*2d4583c4SAdrian Chadd 		return (0);
189*2d4583c4SAdrian Chadd 	}
190*2d4583c4SAdrian Chadd 	if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)
191*2d4583c4SAdrian Chadd 		rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);
192*2d4583c4SAdrian Chadd 	return (1);
193*2d4583c4SAdrian Chadd }
194*2d4583c4SAdrian Chadd 
195*2d4583c4SAdrian Chadd static void
196*2d4583c4SAdrian Chadd gcmp_setiv(struct ieee80211_key *k, uint8_t *ivp)
197*2d4583c4SAdrian Chadd {
198*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
199*2d4583c4SAdrian Chadd 	struct ieee80211vap *vap = ctx->cc_vap;
200*2d4583c4SAdrian Chadd 	uint8_t keyid;
201*2d4583c4SAdrian Chadd 
202*2d4583c4SAdrian Chadd 	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
203*2d4583c4SAdrian Chadd 
204*2d4583c4SAdrian Chadd 	k->wk_keytsc++;
205*2d4583c4SAdrian Chadd 	ivp[0] = k->wk_keytsc >> 0;		/* PN0 */
206*2d4583c4SAdrian Chadd 	ivp[1] = k->wk_keytsc >> 8;		/* PN1 */
207*2d4583c4SAdrian Chadd 	ivp[2] = 0;				/* Reserved */
208*2d4583c4SAdrian Chadd 	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
209*2d4583c4SAdrian Chadd 	ivp[4] = k->wk_keytsc >> 16;		/* PN2 */
210*2d4583c4SAdrian Chadd 	ivp[5] = k->wk_keytsc >> 24;		/* PN3 */
211*2d4583c4SAdrian Chadd 	ivp[6] = k->wk_keytsc >> 32;		/* PN4 */
212*2d4583c4SAdrian Chadd 	ivp[7] = k->wk_keytsc >> 40;		/* PN5 */
213*2d4583c4SAdrian Chadd }
214*2d4583c4SAdrian Chadd 
215*2d4583c4SAdrian Chadd /*
216*2d4583c4SAdrian Chadd  * Add privacy headers appropriate for the specified key.
217*2d4583c4SAdrian Chadd  */
218*2d4583c4SAdrian Chadd static int
219*2d4583c4SAdrian Chadd gcmp_encap(struct ieee80211_key *k, struct mbuf *m)
220*2d4583c4SAdrian Chadd {
221*2d4583c4SAdrian Chadd 	const struct ieee80211_frame *wh;
222*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
223*2d4583c4SAdrian Chadd 	struct ieee80211com *ic = ctx->cc_ic;
224*2d4583c4SAdrian Chadd 	uint8_t *ivp;
225*2d4583c4SAdrian Chadd 	int hdrlen;
226*2d4583c4SAdrian Chadd 	int is_mgmt;
227*2d4583c4SAdrian Chadd 
228*2d4583c4SAdrian Chadd 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
229*2d4583c4SAdrian Chadd 	wh = mtod(m, const struct ieee80211_frame *);
230*2d4583c4SAdrian Chadd 	is_mgmt = IEEE80211_IS_MGMT(wh);
231*2d4583c4SAdrian Chadd 
232*2d4583c4SAdrian Chadd 	/*
233*2d4583c4SAdrian Chadd 	 * Check to see if we need to insert IV/MIC.
234*2d4583c4SAdrian Chadd 	 *
235*2d4583c4SAdrian Chadd 	 * Some offload devices don't require the IV to be inserted
236*2d4583c4SAdrian Chadd 	 * as part of the hardware encryption.
237*2d4583c4SAdrian Chadd 	 */
238*2d4583c4SAdrian Chadd 	if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT))
239*2d4583c4SAdrian Chadd 		return (1);
240*2d4583c4SAdrian Chadd 	if (!is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIV))
241*2d4583c4SAdrian Chadd 		return (1);
242*2d4583c4SAdrian Chadd 
243*2d4583c4SAdrian Chadd 	/*
244*2d4583c4SAdrian Chadd 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
245*2d4583c4SAdrian Chadd 	 */
246*2d4583c4SAdrian Chadd 	M_PREPEND(m, gcmp_get_header_len(k), IEEE80211_M_NOWAIT);
247*2d4583c4SAdrian Chadd 	if (m == NULL)
248*2d4583c4SAdrian Chadd 		return (0);
249*2d4583c4SAdrian Chadd 	ivp = mtod(m, uint8_t *);
250*2d4583c4SAdrian Chadd 	ovbcopy(ivp + gcmp_get_header_len(k), ivp, hdrlen);
251*2d4583c4SAdrian Chadd 	ivp += hdrlen;
252*2d4583c4SAdrian Chadd 
253*2d4583c4SAdrian Chadd 	gcmp_setiv(k, ivp);
254*2d4583c4SAdrian Chadd 
255*2d4583c4SAdrian Chadd 	/*
256*2d4583c4SAdrian Chadd 	 * Finally, do software encrypt if needed.
257*2d4583c4SAdrian Chadd 	 */
258*2d4583c4SAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
259*2d4583c4SAdrian Chadd 	    !gcmp_encrypt(k, m, hdrlen))
260*2d4583c4SAdrian Chadd 		return (0);
261*2d4583c4SAdrian Chadd 
262*2d4583c4SAdrian Chadd 	return (1);
263*2d4583c4SAdrian Chadd }
264*2d4583c4SAdrian Chadd 
265*2d4583c4SAdrian Chadd /*
266*2d4583c4SAdrian Chadd  * Add MIC to the frame as needed.
267*2d4583c4SAdrian Chadd  */
268*2d4583c4SAdrian Chadd static int
269*2d4583c4SAdrian Chadd gcmp_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
270*2d4583c4SAdrian Chadd {
271*2d4583c4SAdrian Chadd 	return (1);
272*2d4583c4SAdrian Chadd }
273*2d4583c4SAdrian Chadd 
274*2d4583c4SAdrian Chadd static __inline uint64_t
275*2d4583c4SAdrian Chadd READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
276*2d4583c4SAdrian Chadd {
277*2d4583c4SAdrian Chadd 	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
278*2d4583c4SAdrian Chadd 	uint16_t iv16 = (b4 << 0) | (b5 << 8);
279*2d4583c4SAdrian Chadd 	return ((((uint64_t)iv16) << 32) | iv32);
280*2d4583c4SAdrian Chadd }
281*2d4583c4SAdrian Chadd 
282*2d4583c4SAdrian Chadd /*
283*2d4583c4SAdrian Chadd  * Validate and strip privacy headers (and trailer) for a
284*2d4583c4SAdrian Chadd  * received frame. The specified key should be correct but
285*2d4583c4SAdrian Chadd  * is also verified.
286*2d4583c4SAdrian Chadd  */
287*2d4583c4SAdrian Chadd static int
288*2d4583c4SAdrian Chadd gcmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
289*2d4583c4SAdrian Chadd {
290*2d4583c4SAdrian Chadd 	const struct ieee80211_rx_stats *rxs;
291*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
292*2d4583c4SAdrian Chadd 	struct ieee80211vap *vap = ctx->cc_vap;
293*2d4583c4SAdrian Chadd 	struct ieee80211_frame *wh;
294*2d4583c4SAdrian Chadd 	uint8_t *ivp, tid;
295*2d4583c4SAdrian Chadd 	uint64_t pn;
296*2d4583c4SAdrian Chadd 	bool noreplaycheck;
297*2d4583c4SAdrian Chadd 
298*2d4583c4SAdrian Chadd 	rxs = ieee80211_get_rx_params_ptr(m);
299*2d4583c4SAdrian Chadd 
300*2d4583c4SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) != 0)
301*2d4583c4SAdrian Chadd 		goto finish;
302*2d4583c4SAdrian Chadd 
303*2d4583c4SAdrian Chadd 	/*
304*2d4583c4SAdrian Chadd 	 * Header should have extended IV and sequence number;
305*2d4583c4SAdrian Chadd 	 * verify the former and validate the latter.
306*2d4583c4SAdrian Chadd 	 */
307*2d4583c4SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
308*2d4583c4SAdrian Chadd 	ivp = mtod(m, uint8_t *) + hdrlen;
309*2d4583c4SAdrian Chadd 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
310*2d4583c4SAdrian Chadd 		/*
311*2d4583c4SAdrian Chadd 		 * No extended IV; discard frame.
312*2d4583c4SAdrian Chadd 		 */
313*2d4583c4SAdrian Chadd 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
314*2d4583c4SAdrian Chadd 			"%s", "missing ExtIV for AES-GCM cipher");
315*2d4583c4SAdrian Chadd 		vap->iv_stats.is_rx_gcmpformat++;
316*2d4583c4SAdrian Chadd 		return (0);
317*2d4583c4SAdrian Chadd 	}
318*2d4583c4SAdrian Chadd 	tid = ieee80211_gettid(wh);
319*2d4583c4SAdrian Chadd 	pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
320*2d4583c4SAdrian Chadd 
321*2d4583c4SAdrian Chadd 	noreplaycheck = (k->wk_flags & IEEE80211_KEY_NOREPLAY) != 0;
322*2d4583c4SAdrian Chadd 	noreplaycheck |= (rxs != NULL) &&
323*2d4583c4SAdrian Chadd 	    (rxs->c_pktflags & IEEE80211_RX_F_PN_VALIDATED) != 0;
324*2d4583c4SAdrian Chadd 	if (pn <= k->wk_keyrsc[tid] && !noreplaycheck) {
325*2d4583c4SAdrian Chadd 		/*
326*2d4583c4SAdrian Chadd 		 * Replay violation.
327*2d4583c4SAdrian Chadd 		 */
328*2d4583c4SAdrian Chadd 		ieee80211_notify_replay_failure(vap, wh, k, pn, tid);
329*2d4583c4SAdrian Chadd 		vap->iv_stats.is_rx_gcmpreplay++;
330*2d4583c4SAdrian Chadd 		return (0);
331*2d4583c4SAdrian Chadd 	}
332*2d4583c4SAdrian Chadd 
333*2d4583c4SAdrian Chadd 	/*
334*2d4583c4SAdrian Chadd 	 * Check if the device handled the decrypt in hardware.
335*2d4583c4SAdrian Chadd 	 * If so we just strip the header; otherwise we need to
336*2d4583c4SAdrian Chadd 	 * handle the decrypt in software.  Note that for the
337*2d4583c4SAdrian Chadd 	 * latter we leave the header in place for use in the
338*2d4583c4SAdrian Chadd 	 * decryption work.
339*2d4583c4SAdrian Chadd 	 */
340*2d4583c4SAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
341*2d4583c4SAdrian Chadd 	    !gcmp_decrypt(k, pn, m, hdrlen))
342*2d4583c4SAdrian Chadd 		return (0);
343*2d4583c4SAdrian Chadd 
344*2d4583c4SAdrian Chadd finish:
345*2d4583c4SAdrian Chadd 	/*
346*2d4583c4SAdrian Chadd 	 * Copy up 802.11 header and strip crypto bits.
347*2d4583c4SAdrian Chadd 	 */
348*2d4583c4SAdrian Chadd 	if ((rxs == NULL) || (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) == 0) {
349*2d4583c4SAdrian Chadd 		ovbcopy(mtod(m, void *), mtod(m, uint8_t *) +
350*2d4583c4SAdrian Chadd 		    gcmp_get_header_len(k), hdrlen);
351*2d4583c4SAdrian Chadd 		m_adj(m, gcmp_get_header_len(k));
352*2d4583c4SAdrian Chadd 	}
353*2d4583c4SAdrian Chadd 
354*2d4583c4SAdrian Chadd 	if ((rxs == NULL) || (rxs->c_pktflags & IEEE80211_RX_F_MIC_STRIP) == 0)
355*2d4583c4SAdrian Chadd 		m_adj(m, -gcmp_get_trailer_len(k));
356*2d4583c4SAdrian Chadd 
357*2d4583c4SAdrian Chadd 	/*
358*2d4583c4SAdrian Chadd 	 * Ok to update rsc now.
359*2d4583c4SAdrian Chadd 	 */
360*2d4583c4SAdrian Chadd 	if ((rxs == NULL) || (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) == 0) {
361*2d4583c4SAdrian Chadd 		/*
362*2d4583c4SAdrian Chadd 		 * Do not go backwards in the IEEE80211_KEY_NOREPLAY cases
363*2d4583c4SAdrian Chadd 		 * or in case hardware has checked but frames are arriving
364*2d4583c4SAdrian Chadd 		 * reordered (e.g., LinuxKPI drivers doing RSS which we are
365*2d4583c4SAdrian Chadd 		 * not prepared for at all).
366*2d4583c4SAdrian Chadd 		 */
367*2d4583c4SAdrian Chadd 		if (pn > k->wk_keyrsc[tid])
368*2d4583c4SAdrian Chadd 			k->wk_keyrsc[tid] = pn;
369*2d4583c4SAdrian Chadd 	}
370*2d4583c4SAdrian Chadd 
371*2d4583c4SAdrian Chadd 	return (1);
372*2d4583c4SAdrian Chadd }
373*2d4583c4SAdrian Chadd 
374*2d4583c4SAdrian Chadd /*
375*2d4583c4SAdrian Chadd  * Verify and strip MIC from the frame.
376*2d4583c4SAdrian Chadd  */
377*2d4583c4SAdrian Chadd static int
378*2d4583c4SAdrian Chadd gcmp_demic(struct ieee80211_key *k, struct mbuf *m, int force)
379*2d4583c4SAdrian Chadd {
380*2d4583c4SAdrian Chadd 	return (1);
381*2d4583c4SAdrian Chadd }
382*2d4583c4SAdrian Chadd 
383*2d4583c4SAdrian Chadd /**
384*2d4583c4SAdrian Chadd  * @brief Calculate the AAD required for this frame for AES-GCM.
385*2d4583c4SAdrian Chadd  *
386*2d4583c4SAdrian Chadd  * Note: This code was first copied over from ieee80211_crypto_ccmp.c, so
387*2d4583c4SAdrian Chadd  * it has some CCMP-isms.
388*2d4583c4SAdrian Chadd  *
389*2d4583c4SAdrian Chadd  * NOTE: the first two bytes are a 16 bit big-endian length, which are used
390*2d4583c4SAdrian Chadd  * by AES-CCM.  AES-GCM doesn't require the length at the beginning.
391*2d4583c4SAdrian Chadd  *
392*2d4583c4SAdrian Chadd  * @param wh	802.11 frame to calculate the AAD over
393*2d4583c4SAdrian Chadd  * @param aad	AAD buffer, GCM_AAD_LEN bytes
394*2d4583c4SAdrian Chadd  * @param The AAD length in bytes.
395*2d4583c4SAdrian Chadd  */
396*2d4583c4SAdrian Chadd static int
397*2d4583c4SAdrian Chadd gcmp_init_aad(const struct ieee80211_frame *wh, uint8_t *aad)
398*2d4583c4SAdrian Chadd {
399*2d4583c4SAdrian Chadd 	int aad_len;
400*2d4583c4SAdrian Chadd 
401*2d4583c4SAdrian Chadd 	memset(aad, 0, GCM_AAD_LEN);
402*2d4583c4SAdrian Chadd 
403*2d4583c4SAdrian Chadd #define	IS_QOS_DATA(wh)	IEEE80211_QOS_HAS_SEQ(wh)
404*2d4583c4SAdrian Chadd 	/* AAD:
405*2d4583c4SAdrian Chadd 	 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
406*2d4583c4SAdrian Chadd 	 * A1 | A2 | A3
407*2d4583c4SAdrian Chadd 	 * SC with bits 4..15 (seq#) masked to zero
408*2d4583c4SAdrian Chadd 	 * A4 (if present)
409*2d4583c4SAdrian Chadd 	 * QC (if present)
410*2d4583c4SAdrian Chadd 	 */
411*2d4583c4SAdrian Chadd 	aad[0] = 0;	/* AAD length >> 8 */
412*2d4583c4SAdrian Chadd 	/* NB: aad[1] set below */
413*2d4583c4SAdrian Chadd 
414*2d4583c4SAdrian Chadd 	/*
415*2d4583c4SAdrian Chadd 	 * TODO: go back over this in 802.11-2020 and triple check
416*2d4583c4SAdrian Chadd 	 * the AAD assembly with regards to packet flags.
417*2d4583c4SAdrian Chadd 	 */
418*2d4583c4SAdrian Chadd 
419*2d4583c4SAdrian Chadd 	aad[2] = wh->i_fc[0] & 0x8f;	/* XXX magic #s */
420*2d4583c4SAdrian Chadd 	/*
421*2d4583c4SAdrian Chadd 	 * TODO: 12.5.3.3.3 - bit 14 should always be set; bit 15 masked to 0
422*2d4583c4SAdrian Chadd 	 * if QoS control field, unmasked otherwise
423*2d4583c4SAdrian Chadd 	 */
424*2d4583c4SAdrian Chadd 	aad[3] = wh->i_fc[1] & 0xc7;	/* XXX magic #s */
425*2d4583c4SAdrian Chadd 	/* NB: we know 3 addresses are contiguous */
426*2d4583c4SAdrian Chadd 	memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
427*2d4583c4SAdrian Chadd 	aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
428*2d4583c4SAdrian Chadd 	aad[23] = 0; /* all bits masked */
429*2d4583c4SAdrian Chadd 	/*
430*2d4583c4SAdrian Chadd 	 * Construct variable-length portion of AAD based
431*2d4583c4SAdrian Chadd 	 * on whether this is a 4-address frame/QOS frame.
432*2d4583c4SAdrian Chadd 	 * We always zero-pad to 32 bytes before running it
433*2d4583c4SAdrian Chadd 	 * through the cipher.
434*2d4583c4SAdrian Chadd 	 */
435*2d4583c4SAdrian Chadd 	if (IEEE80211_IS_DSTODS(wh)) {
436*2d4583c4SAdrian Chadd 		IEEE80211_ADDR_COPY(aad + 24,
437*2d4583c4SAdrian Chadd 			((const struct ieee80211_frame_addr4 *)wh)->i_addr4);
438*2d4583c4SAdrian Chadd 		if (IS_QOS_DATA(wh)) {
439*2d4583c4SAdrian Chadd 			const struct ieee80211_qosframe_addr4 *qwh4 =
440*2d4583c4SAdrian Chadd 				(const struct ieee80211_qosframe_addr4 *) wh;
441*2d4583c4SAdrian Chadd 			aad[30] = qwh4->i_qos[0] & 0x0f;/* just priority bits */
442*2d4583c4SAdrian Chadd 			aad[31] = 0;
443*2d4583c4SAdrian Chadd 			aad_len = aad[1] = 22 + IEEE80211_ADDR_LEN + 2;
444*2d4583c4SAdrian Chadd 		} else {
445*2d4583c4SAdrian Chadd 			*(uint16_t *)&aad[30] = 0;
446*2d4583c4SAdrian Chadd 			aad_len = aad[1] = 22 + IEEE80211_ADDR_LEN;
447*2d4583c4SAdrian Chadd 		}
448*2d4583c4SAdrian Chadd 	} else {
449*2d4583c4SAdrian Chadd 		if (IS_QOS_DATA(wh)) {
450*2d4583c4SAdrian Chadd 			const struct ieee80211_qosframe *qwh =
451*2d4583c4SAdrian Chadd 				(const struct ieee80211_qosframe*) wh;
452*2d4583c4SAdrian Chadd 			aad[24] = qwh->i_qos[0] & 0x0f;	/* just priority bits */
453*2d4583c4SAdrian Chadd 			aad[25] = 0;
454*2d4583c4SAdrian Chadd 			aad_len = aad[1] = 22 + 2;
455*2d4583c4SAdrian Chadd 		} else {
456*2d4583c4SAdrian Chadd 			*(uint16_t *)&aad[24] = 0;
457*2d4583c4SAdrian Chadd 			aad_len = aad[1] = 22;
458*2d4583c4SAdrian Chadd 		}
459*2d4583c4SAdrian Chadd 		*(uint16_t *)&aad[26] = 0;
460*2d4583c4SAdrian Chadd 		*(uint32_t *)&aad[28] = 0;
461*2d4583c4SAdrian Chadd 	}
462*2d4583c4SAdrian Chadd #undef	IS_QOS_DATA
463*2d4583c4SAdrian Chadd 
464*2d4583c4SAdrian Chadd 	return (aad_len);
465*2d4583c4SAdrian Chadd }
466*2d4583c4SAdrian Chadd 
467*2d4583c4SAdrian Chadd /*
468*2d4583c4SAdrian Chadd  * Populate the 12 byte / 96 bit IV buffer.
469*2d4583c4SAdrian Chadd  */
470*2d4583c4SAdrian Chadd static int
471*2d4583c4SAdrian Chadd gcmp_init_iv(uint8_t *iv, const struct ieee80211_frame *wh, u_int64_t pn)
472*2d4583c4SAdrian Chadd {
473*2d4583c4SAdrian Chadd 	uint8_t j_pn[GCMP_PN_LEN];
474*2d4583c4SAdrian Chadd 
475*2d4583c4SAdrian Chadd 	/* Construct the pn buffer */
476*2d4583c4SAdrian Chadd 	j_pn[0] = pn >> 40;
477*2d4583c4SAdrian Chadd 	j_pn[1] = pn >> 32;
478*2d4583c4SAdrian Chadd 	j_pn[2] = pn >> 24;
479*2d4583c4SAdrian Chadd 	j_pn[3] = pn >> 16;
480*2d4583c4SAdrian Chadd 	j_pn[4] = pn >> 8;
481*2d4583c4SAdrian Chadd 	j_pn[5] = pn >> 0;
482*2d4583c4SAdrian Chadd 
483*2d4583c4SAdrian Chadd 	memcpy(iv, wh->i_addr2, IEEE80211_ADDR_LEN);
484*2d4583c4SAdrian Chadd 	memcpy(iv + IEEE80211_ADDR_LEN, j_pn, GCMP_PN_LEN);
485*2d4583c4SAdrian Chadd 
486*2d4583c4SAdrian Chadd 	return (GCMP_IV_LEN); /* 96 bits */
487*2d4583c4SAdrian Chadd }
488*2d4583c4SAdrian Chadd 
489*2d4583c4SAdrian Chadd /*
490*2d4583c4SAdrian Chadd  * @brief Encrypt an mbuf.
491*2d4583c4SAdrian Chadd  *
492*2d4583c4SAdrian Chadd  * This uses a temporary memory buffer to encrypt; the
493*2d4583c4SAdrian Chadd  * current AES-GCM code expects things in a contiguous buffer
494*2d4583c4SAdrian Chadd  * and this avoids the need of breaking out the GCTR and
495*2d4583c4SAdrian Chadd  * GHASH routines into using mbuf iterators.
496*2d4583c4SAdrian Chadd  *
497*2d4583c4SAdrian Chadd  * @param key	ieee80211_key to use
498*2d4583c4SAdrian Chadd  * @param mbuf	802.11 frame to encrypt
499*2d4583c4SAdrian Chadd  * @param hdrlen	the length of the 802.11 header, including any padding
500*2d4583c4SAdrian Chadd  * @returns 0 if error, > 0 if OK.
501*2d4583c4SAdrian Chadd  */
502*2d4583c4SAdrian Chadd static int
503*2d4583c4SAdrian Chadd gcmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
504*2d4583c4SAdrian Chadd {
505*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = key->wk_private;
506*2d4583c4SAdrian Chadd 	struct ieee80211_frame *wh;
507*2d4583c4SAdrian Chadd 	struct ieee80211vap *vap = ctx->cc_vap;
508*2d4583c4SAdrian Chadd 	struct mbuf *m = m0;
509*2d4583c4SAdrian Chadd 	int data_len, aad_len, iv_len, ret;
510*2d4583c4SAdrian Chadd 	uint8_t aad[GCM_AAD_LEN];
511*2d4583c4SAdrian Chadd 	uint8_t T[GCMP_MIC_LEN];
512*2d4583c4SAdrian Chadd 	uint8_t iv[GCMP_IV_LEN];
513*2d4583c4SAdrian Chadd 	uint8_t *p_pktbuf = NULL;
514*2d4583c4SAdrian Chadd 	uint8_t *c_pktbuf = NULL;
515*2d4583c4SAdrian Chadd 
516*2d4583c4SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
517*2d4583c4SAdrian Chadd 	data_len = m->m_pkthdr.len - (hdrlen + gcmp_get_header_len(key));
518*2d4583c4SAdrian Chadd 
519*2d4583c4SAdrian Chadd 	ctx->cc_vap->iv_stats.is_crypto_gcmp++;
520*2d4583c4SAdrian Chadd 
521*2d4583c4SAdrian Chadd 	p_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
522*2d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
523*2d4583c4SAdrian Chadd 	if (p_pktbuf == NULL) {
524*2d4583c4SAdrian Chadd 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
525*2d4583c4SAdrian Chadd 		    "%s", "AES-GCM encrypt failed; couldn't allocate buffer");
526*2d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
527*2d4583c4SAdrian Chadd 		return (0);
528*2d4583c4SAdrian Chadd 	}
529*2d4583c4SAdrian Chadd 	c_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
530*2d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
531*2d4583c4SAdrian Chadd 	if (c_pktbuf == NULL) {
532*2d4583c4SAdrian Chadd 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
533*2d4583c4SAdrian Chadd 		    "%s", "AES-GCM encrypt failed; couldn't allocate buffer");
534*2d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
535*2d4583c4SAdrian Chadd 		IEEE80211_FREE(p_pktbuf, M_TEMP);
536*2d4583c4SAdrian Chadd 		return (0);
537*2d4583c4SAdrian Chadd 	}
538*2d4583c4SAdrian Chadd 
539*2d4583c4SAdrian Chadd 	/* Initialise AAD */
540*2d4583c4SAdrian Chadd 	aad_len = gcmp_init_aad(wh, aad);
541*2d4583c4SAdrian Chadd 
542*2d4583c4SAdrian Chadd 	/* Initialise local Nonce to work on */
543*2d4583c4SAdrian Chadd 	/* TODO: rename iv stuff here to nonce */
544*2d4583c4SAdrian Chadd 	iv_len = gcmp_init_iv(iv, wh, key->wk_keytsc);
545*2d4583c4SAdrian Chadd 
546*2d4583c4SAdrian Chadd 	/* Copy mbuf data part into plaintext pktbuf */
547*2d4583c4SAdrian Chadd 	m_copydata(m0, hdrlen + gcmp_get_header_len(key), data_len,
548*2d4583c4SAdrian Chadd 	    p_pktbuf);
549*2d4583c4SAdrian Chadd 
550*2d4583c4SAdrian Chadd 	/* Run encrypt */
551*2d4583c4SAdrian Chadd 	/*
552*2d4583c4SAdrian Chadd 	 * Note: aad + 2 to skip over the 2 byte length populated
553*2d4583c4SAdrian Chadd 	 * at the beginning, since it's based on the AAD code in CCMP.
554*2d4583c4SAdrian Chadd 	 */
555*2d4583c4SAdrian Chadd 	ieee80211_crypto_aes_gcm_ae(&ctx->cc_aes, iv, iv_len,
556*2d4583c4SAdrian Chadd 	    p_pktbuf, data_len, aad + 2, aad_len, c_pktbuf, T);
557*2d4583c4SAdrian Chadd 
558*2d4583c4SAdrian Chadd 	/* Copy data back over mbuf */
559*2d4583c4SAdrian Chadd 	m_copyback(m0, hdrlen + gcmp_get_header_len(key), data_len,
560*2d4583c4SAdrian Chadd 	    c_pktbuf);
561*2d4583c4SAdrian Chadd 
562*2d4583c4SAdrian Chadd 	/* Append MIC */
563*2d4583c4SAdrian Chadd 	ret = m_append(m0, gcmp_get_trailer_len(key), T);
564*2d4583c4SAdrian Chadd 	if (ret == 0) {
565*2d4583c4SAdrian Chadd 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
566*2d4583c4SAdrian Chadd 		    "%s", "AES-GCM encrypt failed; couldn't append T");
567*2d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nospc++;
568*2d4583c4SAdrian Chadd 	}
569*2d4583c4SAdrian Chadd 
570*2d4583c4SAdrian Chadd 	IEEE80211_FREE(p_pktbuf, M_TEMP);
571*2d4583c4SAdrian Chadd 	IEEE80211_FREE(c_pktbuf, M_TEMP);
572*2d4583c4SAdrian Chadd 
573*2d4583c4SAdrian Chadd 	return (ret);
574*2d4583c4SAdrian Chadd }
575*2d4583c4SAdrian Chadd 
576*2d4583c4SAdrian Chadd /*
577*2d4583c4SAdrian Chadd  * @brief Decrypt an mbuf.
578*2d4583c4SAdrian Chadd  *
579*2d4583c4SAdrian Chadd  * This uses a temporary memory buffer to decrypt; the
580*2d4583c4SAdrian Chadd  * current AES-GCM code expects things in a contiguous buffer
581*2d4583c4SAdrian Chadd  * and this avoids the need of breaking out the GCTR and
582*2d4583c4SAdrian Chadd  * GHASH routines into using mbuf iterators.
583*2d4583c4SAdrian Chadd  *
584*2d4583c4SAdrian Chadd  * @param key	ieee80211_key to use
585*2d4583c4SAdrian Chadd  * @param mbuf	802.11 frame to decrypt
586*2d4583c4SAdrian Chadd  * @param hdrlen	the length of the 802.11 header, including any padding
587*2d4583c4SAdrian Chadd  * @returns 0 if error, > 0 if OK.
588*2d4583c4SAdrian Chadd  */
589*2d4583c4SAdrian Chadd static int
590*2d4583c4SAdrian Chadd gcmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m,
591*2d4583c4SAdrian Chadd     int hdrlen)
592*2d4583c4SAdrian Chadd {
593*2d4583c4SAdrian Chadd 	const struct ieee80211_rx_stats *rxs;
594*2d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = key->wk_private;
595*2d4583c4SAdrian Chadd 	struct ieee80211vap *vap = ctx->cc_vap;
596*2d4583c4SAdrian Chadd 	struct ieee80211_frame *wh;
597*2d4583c4SAdrian Chadd 	int data_len, aad_len, iv_len, ret;
598*2d4583c4SAdrian Chadd 	uint8_t aad[GCM_AAD_LEN];
599*2d4583c4SAdrian Chadd 	uint8_t T[GCMP_MIC_LEN];
600*2d4583c4SAdrian Chadd 	uint8_t iv[GCMP_IV_LEN];
601*2d4583c4SAdrian Chadd 	uint8_t *p_pktbuf = NULL;
602*2d4583c4SAdrian Chadd 	uint8_t *c_pktbuf = NULL;
603*2d4583c4SAdrian Chadd 
604*2d4583c4SAdrian Chadd 	rxs = ieee80211_get_rx_params_ptr(m);
605*2d4583c4SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED) != 0)
606*2d4583c4SAdrian Chadd 		return (1);
607*2d4583c4SAdrian Chadd 
608*2d4583c4SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
609*2d4583c4SAdrian Chadd 
610*2d4583c4SAdrian Chadd 	/* Data length doesn't include the MIC at the end */
611*2d4583c4SAdrian Chadd 	data_len = m->m_pkthdr.len -
612*2d4583c4SAdrian Chadd 	    (hdrlen + gcmp_get_header_len(key) + GCMP_MIC_LEN);
613*2d4583c4SAdrian Chadd 
614*2d4583c4SAdrian Chadd 	ctx->cc_vap->iv_stats.is_crypto_gcmp++;
615*2d4583c4SAdrian Chadd 
616*2d4583c4SAdrian Chadd 	p_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
617*2d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
618*2d4583c4SAdrian Chadd 	if (p_pktbuf == NULL) {
619*2d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
620*2d4583c4SAdrian Chadd 		return (0);
621*2d4583c4SAdrian Chadd 	}
622*2d4583c4SAdrian Chadd 	c_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
623*2d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
624*2d4583c4SAdrian Chadd 	if (c_pktbuf == NULL) {
625*2d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
626*2d4583c4SAdrian Chadd 		IEEE80211_FREE(p_pktbuf, M_TEMP);
627*2d4583c4SAdrian Chadd 		return (0);
628*2d4583c4SAdrian Chadd 	}
629*2d4583c4SAdrian Chadd 
630*2d4583c4SAdrian Chadd 	/* Initialise AAD */
631*2d4583c4SAdrian Chadd 	aad_len = gcmp_init_aad(wh, aad);
632*2d4583c4SAdrian Chadd 
633*2d4583c4SAdrian Chadd 	/* Initialise local IV copy to work on */
634*2d4583c4SAdrian Chadd 	iv_len = gcmp_init_iv(iv, wh, pn);
635*2d4583c4SAdrian Chadd 
636*2d4583c4SAdrian Chadd 	/* Copy mbuf into ciphertext pktbuf */
637*2d4583c4SAdrian Chadd 	m_copydata(m, hdrlen + gcmp_get_header_len(key), data_len,
638*2d4583c4SAdrian Chadd 	    c_pktbuf);
639*2d4583c4SAdrian Chadd 
640*2d4583c4SAdrian Chadd 	/* Copy the MIC into the tag buffer */
641*2d4583c4SAdrian Chadd 	m_copydata(m, hdrlen + gcmp_get_header_len(key) + data_len,
642*2d4583c4SAdrian Chadd 	    GCMP_MIC_LEN, T);
643*2d4583c4SAdrian Chadd 
644*2d4583c4SAdrian Chadd 	/* Run decrypt */
645*2d4583c4SAdrian Chadd 	/*
646*2d4583c4SAdrian Chadd 	 * Note: aad + 2 to skip over the 2 byte length populated
647*2d4583c4SAdrian Chadd 	 * at the beginning, since it's based on the AAD code in CCMP.
648*2d4583c4SAdrian Chadd 	 */
649*2d4583c4SAdrian Chadd 	ret = ieee80211_crypto_aes_gcm_ad(&ctx->cc_aes, iv, iv_len,
650*2d4583c4SAdrian Chadd 	    c_pktbuf, data_len, aad + 2, aad_len, T, p_pktbuf);
651*2d4583c4SAdrian Chadd 
652*2d4583c4SAdrian Chadd 	/* If the MIC was stripped by HW/driver we are done. */
653*2d4583c4SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MIC_STRIP) != 0)
654*2d4583c4SAdrian Chadd 		goto skip_ok;
655*2d4583c4SAdrian Chadd 
656*2d4583c4SAdrian Chadd 	if (ret != 0) {
657*2d4583c4SAdrian Chadd 		/* Decrypt failure */
658*2d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_rx_gcmpmic++;
659*2d4583c4SAdrian Chadd 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
660*2d4583c4SAdrian Chadd 		    "%s", "AES-GCM decrypt failed; MIC mismatch");
661*2d4583c4SAdrian Chadd 		IEEE80211_FREE(p_pktbuf, M_TEMP);
662*2d4583c4SAdrian Chadd 		IEEE80211_FREE(c_pktbuf, M_TEMP);
663*2d4583c4SAdrian Chadd 		return (0);
664*2d4583c4SAdrian Chadd 	}
665*2d4583c4SAdrian Chadd 
666*2d4583c4SAdrian Chadd skip_ok:
667*2d4583c4SAdrian Chadd 	/* Copy data back over mbuf */
668*2d4583c4SAdrian Chadd 	m_copyback(m, hdrlen + gcmp_get_header_len(key), data_len,
669*2d4583c4SAdrian Chadd 	    p_pktbuf);
670*2d4583c4SAdrian Chadd 
671*2d4583c4SAdrian Chadd 	IEEE80211_FREE(p_pktbuf, M_TEMP);
672*2d4583c4SAdrian Chadd 	IEEE80211_FREE(c_pktbuf, M_TEMP);
673*2d4583c4SAdrian Chadd 
674*2d4583c4SAdrian Chadd 	return (1);
675*2d4583c4SAdrian Chadd }
676*2d4583c4SAdrian Chadd 
677*2d4583c4SAdrian Chadd /*
678*2d4583c4SAdrian Chadd  * Module glue.
679*2d4583c4SAdrian Chadd  */
680*2d4583c4SAdrian Chadd IEEE80211_CRYPTO_MODULE(gcmp, 1);
681*2d4583c4SAdrian Chadd IEEE80211_CRYPTO_MODULE_ADD(gcmp_256);
682