xref: /netbsd-src/sys/opencrypto/cryptosoft.c (revision ee55792f151450e8c80b0c52d56963c8c4df0e64)
1*ee55792fSriastradh /*	$NetBSD: cryptosoft.c,v 1.64 2022/05/22 11:39:27 riastradh Exp $ */
2cdfce9ceSjonathan /*	$FreeBSD: src/sys/opencrypto/cryptosoft.c,v 1.2.2.1 2002/11/21 23:34:23 sam Exp $	*/
3cdfce9ceSjonathan /*	$OpenBSD: cryptosoft.c,v 1.35 2002/04/26 08:43:50 deraadt Exp $	*/
4cdfce9ceSjonathan 
5cdfce9ceSjonathan /*
6cdfce9ceSjonathan  * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
7cdfce9ceSjonathan  *
8cdfce9ceSjonathan  * This code was written by Angelos D. Keromytis in Athens, Greece, in
9cdfce9ceSjonathan  * February 2000. Network Security Technologies Inc. (NSTI) kindly
10cdfce9ceSjonathan  * supported the development of this code.
11cdfce9ceSjonathan  *
12cdfce9ceSjonathan  * Copyright (c) 2000, 2001 Angelos D. Keromytis
13cdfce9ceSjonathan  *
14cdfce9ceSjonathan  * Permission to use, copy, and modify this software with or without fee
15cdfce9ceSjonathan  * is hereby granted, provided that this entire notice is included in
16cdfce9ceSjonathan  * all source code copies of any software which is or includes a copy or
17cdfce9ceSjonathan  * modification of this software.
18cdfce9ceSjonathan  *
19cdfce9ceSjonathan  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
20cdfce9ceSjonathan  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
21cdfce9ceSjonathan  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
22cdfce9ceSjonathan  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
23cdfce9ceSjonathan  * PURPOSE.
24cdfce9ceSjonathan  */
25cdfce9ceSjonathan 
26cdfce9ceSjonathan #include <sys/cdefs.h>
27*ee55792fSriastradh __KERNEL_RCSID(0, "$NetBSD: cryptosoft.c,v 1.64 2022/05/22 11:39:27 riastradh Exp $");
28cdfce9ceSjonathan 
29cdfce9ceSjonathan #include <sys/param.h>
30cdfce9ceSjonathan #include <sys/systm.h>
313ca2c3f4Sknakahara #include <sys/kmem.h>
32cdfce9ceSjonathan #include <sys/mbuf.h>
33cdfce9ceSjonathan #include <sys/sysctl.h>
34cdfce9ceSjonathan #include <sys/errno.h>
359305dd35Schristos #include <sys/cprng.h>
362dd4f4d9Spgoyette #include <sys/module.h>
372dd4f4d9Spgoyette #include <sys/device.h>
38b2fb48e9Sjonathan 
392dd4f4d9Spgoyette #ifdef _KERNEL_OPT
40e5bd2a12Stls #include "opt_ocf.h"
412dd4f4d9Spgoyette #endif
422dd4f4d9Spgoyette 
43cdfce9ceSjonathan #include <opencrypto/cryptodev.h>
44cdfce9ceSjonathan #include <opencrypto/cryptosoft.h>
45cdfce9ceSjonathan #include <opencrypto/xform.h>
46cdfce9ceSjonathan 
477bc6d90cSthorpej #include <opencrypto/cryptosoft_xform.c>
48cdfce9ceSjonathan 
49e7ae23fdSchristos #include "ioconf.h"
50e7ae23fdSchristos 
517bc6d90cSthorpej union authctx {
527bc6d90cSthorpej 	MD5_CTX md5ctx;
537bc6d90cSthorpej 	SHA1_CTX sha1ctx;
547bc6d90cSthorpej 	RMD160_CTX rmd160ctx;
557bc6d90cSthorpej 	SHA256_CTX sha256ctx;
567bc6d90cSthorpej 	SHA384_CTX sha384ctx;
577bc6d90cSthorpej 	SHA512_CTX sha512ctx;
58ebc232a5Sdrochner 	aesxcbc_ctx aesxcbcctx;
590a8dabdaSdrochner 	AES_GMAC_CTX aesgmacctx;
60cdfce9ceSjonathan };
61cdfce9ceSjonathan 
62cdfce9ceSjonathan struct swcr_data **swcr_sessions = NULL;
63cdfce9ceSjonathan u_int32_t swcr_sesnum = 0;
64cdfce9ceSjonathan int32_t swcr_id = -1;
65cdfce9ceSjonathan 
66cdfce9ceSjonathan #define COPYBACK(x, a, b, c, d) \
67cdfce9ceSjonathan 	(x) == CRYPTO_BUF_MBUF ? m_copyback((struct mbuf *)a,b,c,d) \
68cdfce9ceSjonathan 	: cuio_copyback((struct uio *)a,b,c,d)
69cdfce9ceSjonathan #define COPYDATA(x, a, b, c, d) \
70cdfce9ceSjonathan 	(x) == CRYPTO_BUF_MBUF ? m_copydata((struct mbuf *)a,b,c,d) \
71cdfce9ceSjonathan 	: cuio_copydata((struct uio *)a,b,c,d)
72cdfce9ceSjonathan 
732e4e5505Sdrochner static	int swcr_encdec(struct cryptodesc *, const struct swcr_data *, void *, int);
742e4e5505Sdrochner static	int swcr_compdec(struct cryptodesc *, const struct swcr_data *, void *, int, int *);
750a8dabdaSdrochner static	int swcr_combined(struct cryptop *, int);
76cdfce9ceSjonathan static	int swcr_process(void *, struct cryptop *, int);
77cdfce9ceSjonathan static	int swcr_newsession(void *, u_int32_t *, struct cryptoini *);
78*ee55792fSriastradh static void swcr_freesession(void *, u_int64_t);
79cfd5cbf4Sknakahara static void swcr_freesession_internal(struct swcr_data *);
80cdfce9ceSjonathan 
8180c73109Sknakahara static	int swcryptoattach_internal(void);
8280c73109Sknakahara 
83cdfce9ceSjonathan /*
84cdfce9ceSjonathan  * Apply a symmetric encryption/decryption algorithm.
85cdfce9ceSjonathan  */
86cdfce9ceSjonathan static int
swcr_encdec(struct cryptodesc * crd,const struct swcr_data * sw,void * bufv,int outtype)872e4e5505Sdrochner swcr_encdec(struct cryptodesc *crd, const struct swcr_data *sw, void *bufv,
88cdfce9ceSjonathan     int outtype)
89cdfce9ceSjonathan {
9053524e44Schristos 	char *buf = bufv;
91cdfce9ceSjonathan 	unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
92cdfce9ceSjonathan 	unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
937bc6d90cSthorpej 	const struct swcr_enc_xform *exf;
945fafa9c4Sdrochner 	int i, k, j, blks, ivlen;
95cdfce9ceSjonathan 	int count, ind;
96cdfce9ceSjonathan 
97cdfce9ceSjonathan 	exf = sw->sw_exf;
987bc6d90cSthorpej 	blks = exf->enc_xform->blocksize;
995fafa9c4Sdrochner 	ivlen = exf->enc_xform->ivsize;
1005fafa9c4Sdrochner 	KASSERT(exf->reinit ? ivlen <= blks : ivlen == blks);
101cdfce9ceSjonathan 
102cdfce9ceSjonathan 	/* Check for non-padded data */
103cdfce9ceSjonathan 	if (crd->crd_len % blks)
104cdfce9ceSjonathan 		return EINVAL;
105cdfce9ceSjonathan 
106cdfce9ceSjonathan 	/* Initialize the IV */
107cdfce9ceSjonathan 	if (crd->crd_flags & CRD_F_ENCRYPT) {
108cdfce9ceSjonathan 		/* IV explicitly provided ? */
109a8250350Sdrochner 		if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
1105fafa9c4Sdrochner 			memcpy(iv, crd->crd_iv, ivlen);
111a8250350Sdrochner 			if (exf->reinit)
112a8250350Sdrochner 				exf->reinit(sw->sw_kschedule, iv, 0);
113a8250350Sdrochner 		} else if (exf->reinit) {
114a8250350Sdrochner 			exf->reinit(sw->sw_kschedule, 0, iv);
115a8250350Sdrochner 		} else {
116f69a480bSriastradh 			cprng_fast(iv, EALG_MAX_BLOCK_LEN);
117cdfce9ceSjonathan 		}
118cdfce9ceSjonathan 
119cdfce9ceSjonathan 		/* Do we need to write the IV */
120cdfce9ceSjonathan 		if (!(crd->crd_flags & CRD_F_IV_PRESENT)) {
1215fafa9c4Sdrochner 			COPYBACK(outtype, buf, crd->crd_inject, ivlen, iv);
122cdfce9ceSjonathan 		}
123cdfce9ceSjonathan 
124cdfce9ceSjonathan 	} else {	/* Decryption */
125cdfce9ceSjonathan 			/* IV explicitly provided ? */
126cdfce9ceSjonathan 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
1275fafa9c4Sdrochner 			memcpy(iv, crd->crd_iv, ivlen);
128cdfce9ceSjonathan 		else {
129cdfce9ceSjonathan 			/* Get IV off buf */
1305fafa9c4Sdrochner 			COPYDATA(outtype, buf, crd->crd_inject, ivlen, iv);
131cdfce9ceSjonathan 		}
132a8250350Sdrochner 		if (exf->reinit)
133a8250350Sdrochner 			exf->reinit(sw->sw_kschedule, iv, 0);
134cdfce9ceSjonathan 	}
135cdfce9ceSjonathan 
136cdfce9ceSjonathan 	ivp = iv;
137cdfce9ceSjonathan 
138cdfce9ceSjonathan 	if (outtype == CRYPTO_BUF_CONTIG) {
1395fafa9c4Sdrochner 		if (exf->reinit) {
1405fafa9c4Sdrochner 			for (i = crd->crd_skip;
1415fafa9c4Sdrochner 			     i < crd->crd_skip + crd->crd_len; i += blks) {
142cdfce9ceSjonathan 				if (crd->crd_flags & CRD_F_ENCRYPT) {
1435fafa9c4Sdrochner 					exf->encrypt(sw->sw_kschedule, buf + i);
1445fafa9c4Sdrochner 				} else {
1455fafa9c4Sdrochner 					exf->decrypt(sw->sw_kschedule, buf + i);
1465fafa9c4Sdrochner 				}
1475fafa9c4Sdrochner 			}
1485fafa9c4Sdrochner 		} else if (crd->crd_flags & CRD_F_ENCRYPT) {
149cdfce9ceSjonathan 			for (i = crd->crd_skip;
150cdfce9ceSjonathan 			    i < crd->crd_skip + crd->crd_len; i += blks) {
151cdfce9ceSjonathan 				/* XOR with the IV/previous block, as appropriate. */
152cdfce9ceSjonathan 				if (i == crd->crd_skip)
153cdfce9ceSjonathan 					for (k = 0; k < blks; k++)
154cdfce9ceSjonathan 						buf[i + k] ^= ivp[k];
155cdfce9ceSjonathan 				else
156cdfce9ceSjonathan 					for (k = 0; k < blks; k++)
157cdfce9ceSjonathan 						buf[i + k] ^= buf[i + k - blks];
158cdfce9ceSjonathan 				exf->encrypt(sw->sw_kschedule, buf + i);
159cdfce9ceSjonathan 			}
160cdfce9ceSjonathan 		} else {		/* Decrypt */
161cdfce9ceSjonathan 			/*
162cdfce9ceSjonathan 			 * Start at the end, so we don't need to keep the encrypted
163cdfce9ceSjonathan 			 * block as the IV for the next block.
164cdfce9ceSjonathan 			 */
165cdfce9ceSjonathan 			for (i = crd->crd_skip + crd->crd_len - blks;
166cdfce9ceSjonathan 			    i >= crd->crd_skip; i -= blks) {
167cdfce9ceSjonathan 				exf->decrypt(sw->sw_kschedule, buf + i);
168cdfce9ceSjonathan 
169cdfce9ceSjonathan 				/* XOR with the IV/previous block, as appropriate */
170cdfce9ceSjonathan 				if (i == crd->crd_skip)
171cdfce9ceSjonathan 					for (k = 0; k < blks; k++)
172cdfce9ceSjonathan 						buf[i + k] ^= ivp[k];
173cdfce9ceSjonathan 				else
174cdfce9ceSjonathan 					for (k = 0; k < blks; k++)
175cdfce9ceSjonathan 						buf[i + k] ^= buf[i + k - blks];
176cdfce9ceSjonathan 			}
177cdfce9ceSjonathan 		}
178cdfce9ceSjonathan 
179cdfce9ceSjonathan 		return 0;
180cdfce9ceSjonathan 	} else if (outtype == CRYPTO_BUF_MBUF) {
181cdfce9ceSjonathan 		struct mbuf *m = (struct mbuf *) buf;
182cdfce9ceSjonathan 
183cdfce9ceSjonathan 		/* Find beginning of data */
184cdfce9ceSjonathan 		m = m_getptr(m, crd->crd_skip, &k);
185cdfce9ceSjonathan 		if (m == NULL)
186cdfce9ceSjonathan 			return EINVAL;
187cdfce9ceSjonathan 
188cdfce9ceSjonathan 		i = crd->crd_len;
189cdfce9ceSjonathan 
190cdfce9ceSjonathan 		while (i > 0) {
191cdfce9ceSjonathan 			/*
192cdfce9ceSjonathan 			 * If there's insufficient data at the end of
193cdfce9ceSjonathan 			 * an mbuf, we have to do some copying.
194cdfce9ceSjonathan 			 */
195cdfce9ceSjonathan 			if (m->m_len < k + blks && m->m_len != k) {
196cdfce9ceSjonathan 				m_copydata(m, k, blks, blk);
197cdfce9ceSjonathan 
198cdfce9ceSjonathan 				/* Actual encryption/decryption */
1995fafa9c4Sdrochner 				if (exf->reinit) {
200cdfce9ceSjonathan 					if (crd->crd_flags & CRD_F_ENCRYPT) {
2015fafa9c4Sdrochner 						exf->encrypt(sw->sw_kschedule,
2025fafa9c4Sdrochner 							     blk);
2035fafa9c4Sdrochner 					} else {
2045fafa9c4Sdrochner 						exf->decrypt(sw->sw_kschedule,
2055fafa9c4Sdrochner 							     blk);
2065fafa9c4Sdrochner 					}
2075fafa9c4Sdrochner 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
208cdfce9ceSjonathan 					/* XOR with previous block */
209cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
210cdfce9ceSjonathan 						blk[j] ^= ivp[j];
211cdfce9ceSjonathan 
212cdfce9ceSjonathan 					exf->encrypt(sw->sw_kschedule, blk);
213cdfce9ceSjonathan 
214cdfce9ceSjonathan 					/*
215cdfce9ceSjonathan 					 * Keep encrypted block for XOR'ing
216cdfce9ceSjonathan 					 * with next block
217cdfce9ceSjonathan 					 */
218e2cb8590Scegger 					memcpy(iv, blk, blks);
219cdfce9ceSjonathan 					ivp = iv;
220cdfce9ceSjonathan 				} else {	/* decrypt */
221cdfce9ceSjonathan 					/*
222cdfce9ceSjonathan 					 * Keep encrypted block for XOR'ing
223cdfce9ceSjonathan 					 * with next block
224cdfce9ceSjonathan 					 */
225cdfce9ceSjonathan 					if (ivp == iv)
226e2cb8590Scegger 						memcpy(piv, blk, blks);
227cdfce9ceSjonathan 					else
228e2cb8590Scegger 						memcpy(iv, blk, blks);
229cdfce9ceSjonathan 
230cdfce9ceSjonathan 					exf->decrypt(sw->sw_kschedule, blk);
231cdfce9ceSjonathan 
232cdfce9ceSjonathan 					/* XOR with previous block */
233cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
234cdfce9ceSjonathan 						blk[j] ^= ivp[j];
235cdfce9ceSjonathan 
236cdfce9ceSjonathan 					if (ivp == iv)
237e2cb8590Scegger 						memcpy(iv, piv, blks);
238cdfce9ceSjonathan 					else
239cdfce9ceSjonathan 						ivp = iv;
240cdfce9ceSjonathan 				}
241cdfce9ceSjonathan 
242cdfce9ceSjonathan 				/* Copy back decrypted block */
243cdfce9ceSjonathan 				m_copyback(m, k, blks, blk);
244cdfce9ceSjonathan 
245cdfce9ceSjonathan 				/* Advance pointer */
246cdfce9ceSjonathan 				m = m_getptr(m, k + blks, &k);
247cdfce9ceSjonathan 				if (m == NULL)
248cdfce9ceSjonathan 					return EINVAL;
249cdfce9ceSjonathan 
250cdfce9ceSjonathan 				i -= blks;
251cdfce9ceSjonathan 
252cdfce9ceSjonathan 				/* Could be done... */
253cdfce9ceSjonathan 				if (i == 0)
254cdfce9ceSjonathan 					break;
255cdfce9ceSjonathan 			}
256cdfce9ceSjonathan 
257cdfce9ceSjonathan 			/* Skip possibly empty mbufs */
258cdfce9ceSjonathan 			if (k == m->m_len) {
259cdfce9ceSjonathan 				for (m = m->m_next; m && m->m_len == 0;
260cdfce9ceSjonathan 				    m = m->m_next)
261cdfce9ceSjonathan 					;
262cdfce9ceSjonathan 				k = 0;
263cdfce9ceSjonathan 			}
264cdfce9ceSjonathan 
265cdfce9ceSjonathan 			/* Sanity check */
266cdfce9ceSjonathan 			if (m == NULL)
267cdfce9ceSjonathan 				return EINVAL;
268cdfce9ceSjonathan 
269cdfce9ceSjonathan 			/*
270cdfce9ceSjonathan 			 * Warning: idat may point to garbage here, but
271cdfce9ceSjonathan 			 * we only use it in the while() loop, only if
272cdfce9ceSjonathan 			 * there are indeed enough data.
273cdfce9ceSjonathan 			 */
274cdfce9ceSjonathan 			idat = mtod(m, unsigned char *) + k;
275cdfce9ceSjonathan 
276cdfce9ceSjonathan 			while (m->m_len >= k + blks && i > 0) {
2775fafa9c4Sdrochner 				if (exf->reinit) {
278cdfce9ceSjonathan 					if (crd->crd_flags & CRD_F_ENCRYPT) {
2795fafa9c4Sdrochner 						exf->encrypt(sw->sw_kschedule,
2805fafa9c4Sdrochner 							     idat);
2815fafa9c4Sdrochner 					} else {
2825fafa9c4Sdrochner 						exf->decrypt(sw->sw_kschedule,
2835fafa9c4Sdrochner 							     idat);
2845fafa9c4Sdrochner 					}
2855fafa9c4Sdrochner 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
286cdfce9ceSjonathan 					/* XOR with previous block/IV */
287cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
288cdfce9ceSjonathan 						idat[j] ^= ivp[j];
289cdfce9ceSjonathan 
290cdfce9ceSjonathan 					exf->encrypt(sw->sw_kschedule, idat);
291cdfce9ceSjonathan 					ivp = idat;
292cdfce9ceSjonathan 				} else {	/* decrypt */
293cdfce9ceSjonathan 					/*
294cdfce9ceSjonathan 					 * Keep encrypted block to be used
295cdfce9ceSjonathan 					 * in next block's processing.
296cdfce9ceSjonathan 					 */
297cdfce9ceSjonathan 					if (ivp == iv)
298e2cb8590Scegger 						memcpy(piv, idat, blks);
299cdfce9ceSjonathan 					else
300e2cb8590Scegger 						memcpy(iv, idat, blks);
301cdfce9ceSjonathan 
302cdfce9ceSjonathan 					exf->decrypt(sw->sw_kschedule, idat);
303cdfce9ceSjonathan 
304cdfce9ceSjonathan 					/* XOR with previous block/IV */
305cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
306cdfce9ceSjonathan 						idat[j] ^= ivp[j];
307cdfce9ceSjonathan 
308cdfce9ceSjonathan 					if (ivp == iv)
309e2cb8590Scegger 						memcpy(iv, piv, blks);
310cdfce9ceSjonathan 					else
311cdfce9ceSjonathan 						ivp = iv;
312cdfce9ceSjonathan 				}
313cdfce9ceSjonathan 
314cdfce9ceSjonathan 				idat += blks;
315cdfce9ceSjonathan 				k += blks;
316cdfce9ceSjonathan 				i -= blks;
317cdfce9ceSjonathan 			}
318cdfce9ceSjonathan 		}
319cdfce9ceSjonathan 
320cdfce9ceSjonathan 		return 0; /* Done with mbuf encryption/decryption */
321cdfce9ceSjonathan 	} else if (outtype == CRYPTO_BUF_IOV) {
322cdfce9ceSjonathan 		struct uio *uio = (struct uio *) buf;
323cdfce9ceSjonathan 
324cdfce9ceSjonathan 		/* Find beginning of data */
325cdfce9ceSjonathan 		count = crd->crd_skip;
326cdfce9ceSjonathan 		ind = cuio_getptr(uio, count, &k);
327cdfce9ceSjonathan 		if (ind == -1)
328cdfce9ceSjonathan 			return EINVAL;
329cdfce9ceSjonathan 
330cdfce9ceSjonathan 		i = crd->crd_len;
331cdfce9ceSjonathan 
332cdfce9ceSjonathan 		while (i > 0) {
333cdfce9ceSjonathan 			/*
334cdfce9ceSjonathan 			 * If there's insufficient data at the end,
335cdfce9ceSjonathan 			 * we have to do some copying.
336cdfce9ceSjonathan 			 */
337cdfce9ceSjonathan 			if (uio->uio_iov[ind].iov_len < k + blks &&
338cdfce9ceSjonathan 			    uio->uio_iov[ind].iov_len != k) {
339cdfce9ceSjonathan 				cuio_copydata(uio, k, blks, blk);
340cdfce9ceSjonathan 
341cdfce9ceSjonathan 				/* Actual encryption/decryption */
3425fafa9c4Sdrochner 				if (exf->reinit) {
343cdfce9ceSjonathan 					if (crd->crd_flags & CRD_F_ENCRYPT) {
3445fafa9c4Sdrochner 						exf->encrypt(sw->sw_kschedule,
3455fafa9c4Sdrochner 							     blk);
3465fafa9c4Sdrochner 					} else {
3475fafa9c4Sdrochner 						exf->decrypt(sw->sw_kschedule,
3485fafa9c4Sdrochner 							     blk);
3495fafa9c4Sdrochner 					}
3505fafa9c4Sdrochner 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
351cdfce9ceSjonathan 					/* XOR with previous block */
352cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
353cdfce9ceSjonathan 						blk[j] ^= ivp[j];
354cdfce9ceSjonathan 
355cdfce9ceSjonathan 					exf->encrypt(sw->sw_kschedule, blk);
356cdfce9ceSjonathan 
357cdfce9ceSjonathan 					/*
358cdfce9ceSjonathan 					 * Keep encrypted block for XOR'ing
359cdfce9ceSjonathan 					 * with next block
360cdfce9ceSjonathan 					 */
361e2cb8590Scegger 					memcpy(iv, blk, blks);
362cdfce9ceSjonathan 					ivp = iv;
363cdfce9ceSjonathan 				} else {	/* decrypt */
364cdfce9ceSjonathan 					/*
365cdfce9ceSjonathan 					 * Keep encrypted block for XOR'ing
366cdfce9ceSjonathan 					 * with next block
367cdfce9ceSjonathan 					 */
368cdfce9ceSjonathan 					if (ivp == iv)
369e2cb8590Scegger 						memcpy(piv, blk, blks);
370cdfce9ceSjonathan 					else
371e2cb8590Scegger 						memcpy(iv, blk, blks);
372cdfce9ceSjonathan 
373cdfce9ceSjonathan 					exf->decrypt(sw->sw_kschedule, blk);
374cdfce9ceSjonathan 
375cdfce9ceSjonathan 					/* XOR with previous block */
376cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
377cdfce9ceSjonathan 						blk[j] ^= ivp[j];
378cdfce9ceSjonathan 
379cdfce9ceSjonathan 					if (ivp == iv)
380e2cb8590Scegger 						memcpy(iv, piv, blks);
381cdfce9ceSjonathan 					else
382cdfce9ceSjonathan 						ivp = iv;
383cdfce9ceSjonathan 				}
384cdfce9ceSjonathan 
385cdfce9ceSjonathan 				/* Copy back decrypted block */
386cdfce9ceSjonathan 				cuio_copyback(uio, k, blks, blk);
387cdfce9ceSjonathan 
388cdfce9ceSjonathan 				count += blks;
389cdfce9ceSjonathan 
390cdfce9ceSjonathan 				/* Advance pointer */
391cdfce9ceSjonathan 				ind = cuio_getptr(uio, count, &k);
392cdfce9ceSjonathan 				if (ind == -1)
393cdfce9ceSjonathan 					return (EINVAL);
394cdfce9ceSjonathan 
395cdfce9ceSjonathan 				i -= blks;
396cdfce9ceSjonathan 
397cdfce9ceSjonathan 				/* Could be done... */
398cdfce9ceSjonathan 				if (i == 0)
399cdfce9ceSjonathan 					break;
400cdfce9ceSjonathan 			}
401cdfce9ceSjonathan 
402cdfce9ceSjonathan 			/*
403cdfce9ceSjonathan 			 * Warning: idat may point to garbage here, but
404cdfce9ceSjonathan 			 * we only use it in the while() loop, only if
405cdfce9ceSjonathan 			 * there are indeed enough data.
406cdfce9ceSjonathan 			 */
40753524e44Schristos 			idat = ((char *)uio->uio_iov[ind].iov_base) + k;
408cdfce9ceSjonathan 
409cdfce9ceSjonathan 			while (uio->uio_iov[ind].iov_len >= k + blks &&
410cdfce9ceSjonathan 			    i > 0) {
4115fafa9c4Sdrochner 				if (exf->reinit) {
412cdfce9ceSjonathan 					if (crd->crd_flags & CRD_F_ENCRYPT) {
4135fafa9c4Sdrochner 						exf->encrypt(sw->sw_kschedule,
4145fafa9c4Sdrochner 							    idat);
4155fafa9c4Sdrochner 					} else {
4165fafa9c4Sdrochner 						exf->decrypt(sw->sw_kschedule,
4175fafa9c4Sdrochner 							    idat);
4185fafa9c4Sdrochner 					}
4195fafa9c4Sdrochner 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
420cdfce9ceSjonathan 					/* XOR with previous block/IV */
421cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
422cdfce9ceSjonathan 						idat[j] ^= ivp[j];
423cdfce9ceSjonathan 
424cdfce9ceSjonathan 					exf->encrypt(sw->sw_kschedule, idat);
425cdfce9ceSjonathan 					ivp = idat;
426cdfce9ceSjonathan 				} else {	/* decrypt */
427cdfce9ceSjonathan 					/*
428cdfce9ceSjonathan 					 * Keep encrypted block to be used
429cdfce9ceSjonathan 					 * in next block's processing.
430cdfce9ceSjonathan 					 */
431cdfce9ceSjonathan 					if (ivp == iv)
432e2cb8590Scegger 						memcpy(piv, idat, blks);
433cdfce9ceSjonathan 					else
434e2cb8590Scegger 						memcpy(iv, idat, blks);
435cdfce9ceSjonathan 
436cdfce9ceSjonathan 					exf->decrypt(sw->sw_kschedule, idat);
437cdfce9ceSjonathan 
438cdfce9ceSjonathan 					/* XOR with previous block/IV */
439cdfce9ceSjonathan 					for (j = 0; j < blks; j++)
440cdfce9ceSjonathan 						idat[j] ^= ivp[j];
441cdfce9ceSjonathan 
442cdfce9ceSjonathan 					if (ivp == iv)
443e2cb8590Scegger 						memcpy(iv, piv, blks);
444cdfce9ceSjonathan 					else
445cdfce9ceSjonathan 						ivp = iv;
446cdfce9ceSjonathan 				}
447cdfce9ceSjonathan 
448cdfce9ceSjonathan 				idat += blks;
449cdfce9ceSjonathan 				count += blks;
450cdfce9ceSjonathan 				k += blks;
451cdfce9ceSjonathan 				i -= blks;
452cdfce9ceSjonathan 			}
453cdfce9ceSjonathan 		}
454cdfce9ceSjonathan 		return 0; /* Done with mbuf encryption/decryption */
455cdfce9ceSjonathan 	}
456cdfce9ceSjonathan 
457cdfce9ceSjonathan 	/* Unreachable */
458cdfce9ceSjonathan 	return EINVAL;
459cdfce9ceSjonathan }
460cdfce9ceSjonathan 
461cdfce9ceSjonathan /*
462cdfce9ceSjonathan  * Compute keyed-hash authenticator.
463cdfce9ceSjonathan  */
464c339e558Sdaniel int
swcr_authcompute(struct cryptop * crp,struct cryptodesc * crd,const struct swcr_data * sw,void * buf,int outtype)465cdfce9ceSjonathan swcr_authcompute(struct cryptop *crp, struct cryptodesc *crd,
4662e4e5505Sdrochner     const struct swcr_data *sw, void *buf, int outtype)
467cdfce9ceSjonathan {
468cdfce9ceSjonathan 	unsigned char aalg[AALG_MAX_RESULT_LEN];
4697bc6d90cSthorpej 	const struct swcr_auth_hash *axf;
470cdfce9ceSjonathan 	union authctx ctx;
471cdfce9ceSjonathan 	int err;
472cdfce9ceSjonathan 
473cdfce9ceSjonathan 	if (sw->sw_ictx == 0)
474cdfce9ceSjonathan 		return EINVAL;
475cdfce9ceSjonathan 
476cdfce9ceSjonathan 	axf = sw->sw_axf;
477cdfce9ceSjonathan 
4789f36e765Sdrochner 	memcpy(&ctx, sw->sw_ictx, axf->ctxsize);
479cdfce9ceSjonathan 
480cdfce9ceSjonathan 	switch (outtype) {
481cdfce9ceSjonathan 	case CRYPTO_BUF_CONTIG:
48253524e44Schristos 		axf->Update(&ctx, (char *)buf + crd->crd_skip, crd->crd_len);
483cdfce9ceSjonathan 		break;
484cdfce9ceSjonathan 	case CRYPTO_BUF_MBUF:
485cdfce9ceSjonathan 		err = m_apply((struct mbuf *) buf, crd->crd_skip, crd->crd_len,
4864ce1278aSchristos 		    (int (*)(void*, void *, unsigned int))(void *)axf->Update,
48753524e44Schristos 		    (void *) &ctx);
488cdfce9ceSjonathan 		if (err)
489cdfce9ceSjonathan 			return err;
490cdfce9ceSjonathan 		break;
491cdfce9ceSjonathan 	case CRYPTO_BUF_IOV:
492de6bc09eSjonathan 		err = cuio_apply((struct uio *) buf, crd->crd_skip,
493de6bc09eSjonathan 		    crd->crd_len,
4944ce1278aSchristos 		    (int (*)(void *, void *, unsigned int))(void *)axf->Update,
49553524e44Schristos 		    (void *) &ctx);
496de6bc09eSjonathan 		if (err) {
497de6bc09eSjonathan 			return err;
498de6bc09eSjonathan 		}
499de6bc09eSjonathan 		break;
500cdfce9ceSjonathan 	default:
501cdfce9ceSjonathan 		return EINVAL;
502cdfce9ceSjonathan 	}
503cdfce9ceSjonathan 
504cdfce9ceSjonathan 	switch (sw->sw_alg) {
505cdfce9ceSjonathan 	case CRYPTO_MD5_HMAC:
506e2205fa0Stls 	case CRYPTO_MD5_HMAC_96:
507cdfce9ceSjonathan 	case CRYPTO_SHA1_HMAC:
508e2205fa0Stls 	case CRYPTO_SHA1_HMAC_96:
509b4da53f1Sdrochner 	case CRYPTO_SHA2_256_HMAC:
510b4da53f1Sdrochner 	case CRYPTO_SHA2_384_HMAC:
511b4da53f1Sdrochner 	case CRYPTO_SHA2_512_HMAC:
512cdfce9ceSjonathan 	case CRYPTO_RIPEMD160_HMAC:
513e2205fa0Stls 	case CRYPTO_RIPEMD160_HMAC_96:
514cdfce9ceSjonathan 		if (sw->sw_octx == NULL)
515cdfce9ceSjonathan 			return EINVAL;
516cdfce9ceSjonathan 
517cdfce9ceSjonathan 		axf->Final(aalg, &ctx);
5189f36e765Sdrochner 		memcpy(&ctx, sw->sw_octx, axf->ctxsize);
5197bc6d90cSthorpej 		axf->Update(&ctx, aalg, axf->auth_hash->hashsize);
520cdfce9ceSjonathan 		axf->Final(aalg, &ctx);
521cdfce9ceSjonathan 		break;
522cdfce9ceSjonathan 
523cdfce9ceSjonathan 	case CRYPTO_MD5_KPDK:
524cdfce9ceSjonathan 	case CRYPTO_SHA1_KPDK:
525cdfce9ceSjonathan 		if (sw->sw_octx == NULL)
526cdfce9ceSjonathan 			return EINVAL;
527cdfce9ceSjonathan 
528cdfce9ceSjonathan 		axf->Update(&ctx, sw->sw_octx, sw->sw_klen);
529cdfce9ceSjonathan 		axf->Final(aalg, &ctx);
530cdfce9ceSjonathan 		break;
531cdfce9ceSjonathan 
532cdfce9ceSjonathan 	case CRYPTO_NULL_HMAC:
533cdfce9ceSjonathan 	case CRYPTO_MD5:
534cdfce9ceSjonathan 	case CRYPTO_SHA1:
535ebc232a5Sdrochner 	case CRYPTO_AES_XCBC_MAC_96:
536cdfce9ceSjonathan 		axf->Final(aalg, &ctx);
537cdfce9ceSjonathan 		break;
538cdfce9ceSjonathan 	}
539cdfce9ceSjonathan 
540cdfce9ceSjonathan 	/* Inject the authentication data */
541de6bc09eSjonathan 	switch (outtype) {
542de6bc09eSjonathan 	case CRYPTO_BUF_CONTIG:
54353524e44Schristos 		(void)memcpy((char *)buf + crd->crd_inject, aalg,
54453524e44Schristos 		    axf->auth_hash->authsize);
545de6bc09eSjonathan 		break;
546de6bc09eSjonathan 	case CRYPTO_BUF_MBUF:
547cdfce9ceSjonathan 		m_copyback((struct mbuf *) buf, crd->crd_inject,
5487bc6d90cSthorpej 		    axf->auth_hash->authsize, aalg);
549de6bc09eSjonathan 		break;
550de6bc09eSjonathan 	case CRYPTO_BUF_IOV:
551e2cb8590Scegger 		memcpy(crp->crp_mac, aalg, axf->auth_hash->authsize);
552de6bc09eSjonathan 		break;
553de6bc09eSjonathan 	default:
554de6bc09eSjonathan 		return EINVAL;
555de6bc09eSjonathan 	}
556cdfce9ceSjonathan 	return 0;
557cdfce9ceSjonathan }
558cdfce9ceSjonathan 
559cdfce9ceSjonathan /*
5600a8dabdaSdrochner  * Apply a combined encryption-authentication transformation
5610a8dabdaSdrochner  */
5620a8dabdaSdrochner static int
swcr_combined(struct cryptop * crp,int outtype)5630a8dabdaSdrochner swcr_combined(struct cryptop *crp, int outtype)
5640a8dabdaSdrochner {
5650a8dabdaSdrochner 	uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))];
5660a8dabdaSdrochner 	u_char *blk = (u_char *)blkbuf;
5670a8dabdaSdrochner 	u_char aalg[AALG_MAX_RESULT_LEN];
5680a8dabdaSdrochner 	u_char iv[EALG_MAX_BLOCK_LEN];
5690a8dabdaSdrochner 	union authctx ctx;
5700a8dabdaSdrochner 	struct cryptodesc *crd, *crda = NULL, *crde = NULL;
5710a8dabdaSdrochner 	struct swcr_data *sw, *swa, *swe = NULL;
5720a8dabdaSdrochner 	const struct swcr_auth_hash *axf = NULL;
5730a8dabdaSdrochner 	const struct swcr_enc_xform *exf = NULL;
5740a8dabdaSdrochner 	void *buf = (void *)crp->crp_buf;
5750a8dabdaSdrochner 	uint32_t *blkp;
5760a8dabdaSdrochner 	int i, blksz = 0, ivlen = 0, len;
5770a8dabdaSdrochner 
5780a8dabdaSdrochner 	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
5790a8dabdaSdrochner 		for (sw = swcr_sessions[crp->crp_sid & 0xffffffff];
5800a8dabdaSdrochner 		     sw && sw->sw_alg != crd->crd_alg;
5810a8dabdaSdrochner 		     sw = sw->sw_next)
5820a8dabdaSdrochner 			;
5830a8dabdaSdrochner 		if (sw == NULL)
5840a8dabdaSdrochner 			return (EINVAL);
5850a8dabdaSdrochner 
5860a8dabdaSdrochner 		switch (sw->sw_alg) {
5870a8dabdaSdrochner 		case CRYPTO_AES_GCM_16:
5880a8dabdaSdrochner 		case CRYPTO_AES_GMAC:
5890a8dabdaSdrochner 			swe = sw;
5900a8dabdaSdrochner 			crde = crd;
5910a8dabdaSdrochner 			exf = swe->sw_exf;
5920a8dabdaSdrochner 			ivlen = exf->enc_xform->ivsize;
5930a8dabdaSdrochner 			break;
5940a8dabdaSdrochner 		case CRYPTO_AES_128_GMAC:
5950a8dabdaSdrochner 		case CRYPTO_AES_192_GMAC:
5960a8dabdaSdrochner 		case CRYPTO_AES_256_GMAC:
5970a8dabdaSdrochner 			swa = sw;
5980a8dabdaSdrochner 			crda = crd;
5990a8dabdaSdrochner 			axf = swa->sw_axf;
6000a8dabdaSdrochner 			if (swa->sw_ictx == 0)
6010a8dabdaSdrochner 				return (EINVAL);
6020a8dabdaSdrochner 			memcpy(&ctx, swa->sw_ictx, axf->ctxsize);
6030a8dabdaSdrochner 			blksz = axf->auth_hash->blocksize;
6040a8dabdaSdrochner 			break;
6050a8dabdaSdrochner 		default:
6060a8dabdaSdrochner 			return (EINVAL);
6070a8dabdaSdrochner 		}
6080a8dabdaSdrochner 	}
6090a8dabdaSdrochner 	if (crde == NULL || crda == NULL)
6100a8dabdaSdrochner 		return (EINVAL);
6110a8dabdaSdrochner 	if (outtype == CRYPTO_BUF_CONTIG)
6120a8dabdaSdrochner 		return (EINVAL);
6130a8dabdaSdrochner 
6140a8dabdaSdrochner 	/* Initialize the IV */
6150a8dabdaSdrochner 	if (crde->crd_flags & CRD_F_ENCRYPT) {
6160a8dabdaSdrochner 		/* IV explicitly provided ? */
6170a8dabdaSdrochner 		if (crde->crd_flags & CRD_F_IV_EXPLICIT) {
6180a8dabdaSdrochner 			memcpy(iv, crde->crd_iv, ivlen);
6190a8dabdaSdrochner 			if (exf->reinit)
6200a8dabdaSdrochner 				exf->reinit(swe->sw_kschedule, iv, 0);
6210a8dabdaSdrochner 		} else if (exf->reinit)
6220a8dabdaSdrochner 			exf->reinit(swe->sw_kschedule, 0, iv);
6230a8dabdaSdrochner 		else
624f27d6532Stls 			cprng_fast(iv, ivlen);
6250a8dabdaSdrochner 
6260a8dabdaSdrochner 		/* Do we need to write the IV */
6270a8dabdaSdrochner 		if (!(crde->crd_flags & CRD_F_IV_PRESENT))
6280a8dabdaSdrochner 			COPYBACK(outtype, buf, crde->crd_inject, ivlen, iv);
6290a8dabdaSdrochner 
6300a8dabdaSdrochner 	} else {	/* Decryption */
6310a8dabdaSdrochner 			/* IV explicitly provided ? */
6320a8dabdaSdrochner 		if (crde->crd_flags & CRD_F_IV_EXPLICIT)
6330a8dabdaSdrochner 			memcpy(iv, crde->crd_iv, ivlen);
6340a8dabdaSdrochner 		else {
6350a8dabdaSdrochner 			/* Get IV off buf */
6360a8dabdaSdrochner 			COPYDATA(outtype, buf, crde->crd_inject, ivlen, iv);
6370a8dabdaSdrochner 		}
6380a8dabdaSdrochner 		if (exf->reinit)
6390a8dabdaSdrochner 			exf->reinit(swe->sw_kschedule, iv, 0);
6400a8dabdaSdrochner 	}
6410a8dabdaSdrochner 
6420a8dabdaSdrochner 	/* Supply MAC with IV */
6430a8dabdaSdrochner 	if (axf->Reinit)
6440a8dabdaSdrochner 		axf->Reinit(&ctx, iv, ivlen);
6450a8dabdaSdrochner 
6460a8dabdaSdrochner 	/* Supply MAC with AAD */
6470a8dabdaSdrochner 	for (i = 0; i < crda->crd_len; i += blksz) {
6480a8dabdaSdrochner 		len = MIN(crda->crd_len - i, blksz);
6490a8dabdaSdrochner 		COPYDATA(outtype, buf, crda->crd_skip + i, len, blk);
6500a8dabdaSdrochner 		axf->Update(&ctx, blk, len);
6510a8dabdaSdrochner 	}
6520a8dabdaSdrochner 
6530a8dabdaSdrochner 	/* Do encryption/decryption with MAC */
6540a8dabdaSdrochner 	for (i = 0; i < crde->crd_len; i += blksz) {
6550a8dabdaSdrochner 		len = MIN(crde->crd_len - i, blksz);
6560a8dabdaSdrochner 		if (len < blksz)
6570a8dabdaSdrochner 			memset(blk, 0, blksz);
6580a8dabdaSdrochner 		COPYDATA(outtype, buf, crde->crd_skip + i, len, blk);
6590a8dabdaSdrochner 		if (crde->crd_flags & CRD_F_ENCRYPT) {
6600a8dabdaSdrochner 			exf->encrypt(swe->sw_kschedule, blk);
6610a8dabdaSdrochner 			axf->Update(&ctx, blk, len);
6620a8dabdaSdrochner 		} else {
6630a8dabdaSdrochner 			axf->Update(&ctx, blk, len);
6640a8dabdaSdrochner 			exf->decrypt(swe->sw_kschedule, blk);
6650a8dabdaSdrochner 		}
6660a8dabdaSdrochner 		COPYBACK(outtype, buf, crde->crd_skip + i, len, blk);
6670a8dabdaSdrochner 	}
6680a8dabdaSdrochner 
6690a8dabdaSdrochner 	/* Do any required special finalization */
6700a8dabdaSdrochner 	switch (crda->crd_alg) {
6710a8dabdaSdrochner 		case CRYPTO_AES_128_GMAC:
6720a8dabdaSdrochner 		case CRYPTO_AES_192_GMAC:
6730a8dabdaSdrochner 		case CRYPTO_AES_256_GMAC:
6740a8dabdaSdrochner 			/* length block */
6750a8dabdaSdrochner 			memset(blk, 0, blksz);
6760a8dabdaSdrochner 			blkp = (uint32_t *)blk + 1;
6770a8dabdaSdrochner 			*blkp = htobe32(crda->crd_len * 8);
6780a8dabdaSdrochner 			blkp = (uint32_t *)blk + 3;
6790a8dabdaSdrochner 			*blkp = htobe32(crde->crd_len * 8);
6800a8dabdaSdrochner 			axf->Update(&ctx, blk, blksz);
6810a8dabdaSdrochner 			break;
6820a8dabdaSdrochner 	}
6830a8dabdaSdrochner 
6840a8dabdaSdrochner 	/* Finalize MAC */
6850a8dabdaSdrochner 	axf->Final(aalg, &ctx);
6860a8dabdaSdrochner 
6870a8dabdaSdrochner 	/* Inject the authentication data */
6880a8dabdaSdrochner 	if (outtype == CRYPTO_BUF_MBUF)
6890a8dabdaSdrochner 		COPYBACK(outtype, buf, crda->crd_inject, axf->auth_hash->authsize, aalg);
6900a8dabdaSdrochner 	else
6910a8dabdaSdrochner 		memcpy(crp->crp_mac, aalg, axf->auth_hash->authsize);
6920a8dabdaSdrochner 
6930a8dabdaSdrochner 	return (0);
6940a8dabdaSdrochner }
6950a8dabdaSdrochner 
6960a8dabdaSdrochner /*
697cdfce9ceSjonathan  * Apply a compression/decompression algorithm
698cdfce9ceSjonathan  */
699cdfce9ceSjonathan static int
swcr_compdec(struct cryptodesc * crd,const struct swcr_data * sw,void * buf,int outtype,int * res_size)7002e4e5505Sdrochner swcr_compdec(struct cryptodesc *crd, const struct swcr_data *sw,
7012e4e5505Sdrochner     void *buf, int outtype, int *res_size)
702cdfce9ceSjonathan {
703cdfce9ceSjonathan 	u_int8_t *data, *out;
7047bc6d90cSthorpej 	const struct swcr_comp_algo *cxf;
705cdfce9ceSjonathan 	int adj;
706cdfce9ceSjonathan 	u_int32_t result;
707cdfce9ceSjonathan 
708cdfce9ceSjonathan 	cxf = sw->sw_cxf;
709cdfce9ceSjonathan 
710cdfce9ceSjonathan 	/* We must handle the whole buffer of data in one time
711cdfce9ceSjonathan 	 * then if there is not all the data in the mbuf, we must
712cdfce9ceSjonathan 	 * copy in a buffer.
713cdfce9ceSjonathan 	 */
714cdfce9ceSjonathan 
7155b59f58dSknakahara 	data = malloc(crd->crd_len, M_CRYPTO_DATA, M_NOWAIT);
716cdfce9ceSjonathan 	if (data == NULL)
717cdfce9ceSjonathan 		return (EINVAL);
718cdfce9ceSjonathan 	COPYDATA(outtype, buf, crd->crd_skip, crd->crd_len, data);
719cdfce9ceSjonathan 
720cdfce9ceSjonathan 	if (crd->crd_flags & CRD_F_COMP)
721cdfce9ceSjonathan 		result = cxf->compress(data, crd->crd_len, &out);
722cdfce9ceSjonathan 	else
7231caa9a52Sdrochner 		result = cxf->decompress(data, crd->crd_len, &out,
7241caa9a52Sdrochner 					 *res_size);
725cdfce9ceSjonathan 
7265b59f58dSknakahara 	free(data, M_CRYPTO_DATA);
727cdfce9ceSjonathan 	if (result == 0)
728cdfce9ceSjonathan 		return EINVAL;
729cdfce9ceSjonathan 
730cdfce9ceSjonathan 	/* Copy back the (de)compressed data. m_copyback is
731cdfce9ceSjonathan 	 * extending the mbuf as necessary.
732cdfce9ceSjonathan 	 */
7332e4e5505Sdrochner 	*res_size = (int)result;
734cdfce9ceSjonathan 	/* Check the compressed size when doing compression */
7351caa9a52Sdrochner 	if (crd->crd_flags & CRD_F_COMP &&
7361caa9a52Sdrochner 	    sw->sw_alg == CRYPTO_DEFLATE_COMP_NOGROW &&
7371caa9a52Sdrochner 	    result >= crd->crd_len) {
738cdfce9ceSjonathan 			/* Compression was useless, we lost time */
7399b87d582Scegger 			free(out, M_CRYPTO_DATA);
740cdfce9ceSjonathan 			return 0;
741cdfce9ceSjonathan 	}
742cdfce9ceSjonathan 
743cdfce9ceSjonathan 	COPYBACK(outtype, buf, crd->crd_skip, result, out);
744cdfce9ceSjonathan 	if (result < crd->crd_len) {
745cdfce9ceSjonathan 		adj = result - crd->crd_len;
746cdfce9ceSjonathan 		if (outtype == CRYPTO_BUF_MBUF) {
747cdfce9ceSjonathan 			m_adj((struct mbuf *)buf, adj);
748cdfce9ceSjonathan 		}
74936ea3668Sdarran 		/* Don't adjust the iov_len, it breaks the kmem_free */
750cdfce9ceSjonathan 	}
7519b87d582Scegger 	free(out, M_CRYPTO_DATA);
752cdfce9ceSjonathan 	return 0;
753cdfce9ceSjonathan }
754cdfce9ceSjonathan 
755cdfce9ceSjonathan /*
756cdfce9ceSjonathan  * Generate a new software session.
757cdfce9ceSjonathan  */
758cdfce9ceSjonathan static int
swcr_newsession(void * arg,u_int32_t * sid,struct cryptoini * cri)759168cd830Schristos swcr_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)
760cdfce9ceSjonathan {
761cdfce9ceSjonathan 	struct swcr_data **swd;
762cfd5cbf4Sknakahara 	struct swcr_data *first, *tmp;
7637bc6d90cSthorpej 	const struct swcr_auth_hash *axf;
7647bc6d90cSthorpej 	const struct swcr_enc_xform *txf;
7657bc6d90cSthorpej 	const struct swcr_comp_algo *cxf;
766cdfce9ceSjonathan 	u_int32_t i;
767cdfce9ceSjonathan 	int k, error;
768cdfce9ceSjonathan 
769cdfce9ceSjonathan 	if (swcr_sessions) {
770cdfce9ceSjonathan 		for (i = 1; i < swcr_sesnum; i++)
771cdfce9ceSjonathan 			if (swcr_sessions[i] == NULL)
772cdfce9ceSjonathan 				break;
773cdfce9ceSjonathan 	} else
774cdfce9ceSjonathan 		i = 1;		/* NB: to silence compiler warning */
775cdfce9ceSjonathan 
776cdfce9ceSjonathan 	if (swcr_sessions == NULL || i == swcr_sesnum) {
77759a04e4aSknakahara 		u_int32_t newnum;
77859a04e4aSknakahara 		struct swcr_data **newsessions;
77959a04e4aSknakahara 
780cdfce9ceSjonathan 		if (swcr_sessions == NULL) {
781cdfce9ceSjonathan 			i = 1; /* We leave swcr_sessions[0] empty */
78259a04e4aSknakahara 			newnum = CRYPTO_SW_SESSIONS;
783cdfce9ceSjonathan 		} else
78459a04e4aSknakahara 			newnum = swcr_sesnum *= 2;
785cdfce9ceSjonathan 
78659a04e4aSknakahara 		newsessions = kmem_zalloc(newnum * sizeof(struct swcr_data *),
7873ca2c3f4Sknakahara 		    KM_NOSLEEP);
78859a04e4aSknakahara 		if (newsessions == NULL) {
789cdfce9ceSjonathan 			return ENOBUFS;
790cdfce9ceSjonathan 		}
791cdfce9ceSjonathan 
792cdfce9ceSjonathan 		/* Copy existing sessions */
793cdfce9ceSjonathan 		if (swcr_sessions) {
79459a04e4aSknakahara 			memcpy(newsessions, swcr_sessions,
79559a04e4aSknakahara 			    swcr_sesnum * sizeof(struct swcr_data *));
7963ca2c3f4Sknakahara 			kmem_free(swcr_sessions,
79759a04e4aSknakahara 			    swcr_sesnum * sizeof(struct swcr_data *));
798cdfce9ceSjonathan 		}
799cdfce9ceSjonathan 
80059a04e4aSknakahara 		swcr_sesnum = newnum;
80159a04e4aSknakahara 		swcr_sessions = newsessions;
802cdfce9ceSjonathan 	}
803cdfce9ceSjonathan 
804cfd5cbf4Sknakahara 	first = NULL;
805cfd5cbf4Sknakahara 	swd = &tmp;
806cdfce9ceSjonathan 	while (cri) {
8073ca2c3f4Sknakahara 		*swd = kmem_zalloc(sizeof **swd, KM_NOSLEEP);
808cdfce9ceSjonathan 		if (*swd == NULL) {
809cfd5cbf4Sknakahara 			if (first != NULL)
810cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
811cdfce9ceSjonathan 			return ENOBUFS;
812cfd5cbf4Sknakahara 		} else if (first == NULL)
813cfd5cbf4Sknakahara 			first = *swd;
814cdfce9ceSjonathan 
815cdfce9ceSjonathan 		switch (cri->cri_alg) {
816cdfce9ceSjonathan 		case CRYPTO_DES_CBC:
8177bc6d90cSthorpej 			txf = &swcr_enc_xform_des;
818cdfce9ceSjonathan 			goto enccommon;
819cdfce9ceSjonathan 		case CRYPTO_3DES_CBC:
8207bc6d90cSthorpej 			txf = &swcr_enc_xform_3des;
821cdfce9ceSjonathan 			goto enccommon;
822cdfce9ceSjonathan 		case CRYPTO_BLF_CBC:
8237bc6d90cSthorpej 			txf = &swcr_enc_xform_blf;
824cdfce9ceSjonathan 			goto enccommon;
825cdfce9ceSjonathan 		case CRYPTO_CAST_CBC:
8267bc6d90cSthorpej 			txf = &swcr_enc_xform_cast5;
827cdfce9ceSjonathan 			goto enccommon;
828cdfce9ceSjonathan 		case CRYPTO_SKIPJACK_CBC:
8297bc6d90cSthorpej 			txf = &swcr_enc_xform_skipjack;
830cdfce9ceSjonathan 			goto enccommon;
8318835ffd0Sriastradh 		case CRYPTO_AES_CBC:
8328835ffd0Sriastradh 			txf = &swcr_enc_xform_aes;
833cdfce9ceSjonathan 			goto enccommon;
8343d2cef17Sdrochner 		case CRYPTO_CAMELLIA_CBC:
8353d2cef17Sdrochner 			txf = &swcr_enc_xform_camellia;
8363d2cef17Sdrochner 			goto enccommon;
8373e66cf48Sdrochner 		case CRYPTO_AES_CTR:
8383e66cf48Sdrochner 			txf = &swcr_enc_xform_aes_ctr;
8393e66cf48Sdrochner 			goto enccommon;
8400a8dabdaSdrochner 		case CRYPTO_AES_GCM_16:
8410a8dabdaSdrochner 			txf = &swcr_enc_xform_aes_gcm;
8420a8dabdaSdrochner 			goto enccommon;
84349c12b7aSdrochner 		case CRYPTO_AES_GMAC:
84449c12b7aSdrochner 			txf = &swcr_enc_xform_aes_gmac;
84549c12b7aSdrochner 			goto enccommon;
846cdfce9ceSjonathan 		case CRYPTO_NULL_CBC:
8477bc6d90cSthorpej 			txf = &swcr_enc_xform_null;
848cdfce9ceSjonathan 			goto enccommon;
849cdfce9ceSjonathan 		enccommon:
850cdfce9ceSjonathan 			error = txf->setkey(&((*swd)->sw_kschedule),
851cdfce9ceSjonathan 					cri->cri_key, cri->cri_klen / 8);
852cdfce9ceSjonathan 			if (error) {
853cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
854cdfce9ceSjonathan 				return error;
855cdfce9ceSjonathan 			}
856cdfce9ceSjonathan 			(*swd)->sw_exf = txf;
857cdfce9ceSjonathan 			break;
858cdfce9ceSjonathan 
859cdfce9ceSjonathan 		case CRYPTO_MD5_HMAC:
860e2205fa0Stls 			axf = &swcr_auth_hash_hmac_md5;
861e2205fa0Stls 			goto authcommon;
862e2205fa0Stls 		case CRYPTO_MD5_HMAC_96:
8637bc6d90cSthorpej 			axf = &swcr_auth_hash_hmac_md5_96;
864cdfce9ceSjonathan 			goto authcommon;
865cdfce9ceSjonathan 		case CRYPTO_SHA1_HMAC:
866e2205fa0Stls 			axf = &swcr_auth_hash_hmac_sha1;
867e2205fa0Stls 			goto authcommon;
868e2205fa0Stls 		case CRYPTO_SHA1_HMAC_96:
8697bc6d90cSthorpej 			axf = &swcr_auth_hash_hmac_sha1_96;
870cdfce9ceSjonathan 			goto authcommon;
871b4da53f1Sdrochner 		case CRYPTO_SHA2_256_HMAC:
8727bc6d90cSthorpej 			axf = &swcr_auth_hash_hmac_sha2_256;
873b4da53f1Sdrochner 			goto authcommon;
874b4da53f1Sdrochner 		case CRYPTO_SHA2_384_HMAC:
8757bc6d90cSthorpej 			axf = &swcr_auth_hash_hmac_sha2_384;
876b4da53f1Sdrochner 			goto authcommon;
877b4da53f1Sdrochner 		case CRYPTO_SHA2_512_HMAC:
8787bc6d90cSthorpej 			axf = &swcr_auth_hash_hmac_sha2_512;
879cdfce9ceSjonathan 			goto authcommon;
880cdfce9ceSjonathan 		case CRYPTO_NULL_HMAC:
8817bc6d90cSthorpej 			axf = &swcr_auth_hash_null;
882cdfce9ceSjonathan 			goto authcommon;
883cdfce9ceSjonathan 		case CRYPTO_RIPEMD160_HMAC:
884e2205fa0Stls 			axf = &swcr_auth_hash_hmac_ripemd_160;
885e2205fa0Stls 			goto authcommon;
886e2205fa0Stls 		case CRYPTO_RIPEMD160_HMAC_96:
8877bc6d90cSthorpej 			axf = &swcr_auth_hash_hmac_ripemd_160_96;
888e2205fa0Stls 			goto authcommon;	/* leave this for safety */
889cdfce9ceSjonathan 		authcommon:
8908835ffd0Sriastradh 			(*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
891cdfce9ceSjonathan 			if ((*swd)->sw_ictx == NULL) {
892cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
893cdfce9ceSjonathan 				return ENOBUFS;
894cdfce9ceSjonathan 			}
895cdfce9ceSjonathan 
8968835ffd0Sriastradh 			(*swd)->sw_octx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
897cdfce9ceSjonathan 			if ((*swd)->sw_octx == NULL) {
898cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
899cdfce9ceSjonathan 				return ENOBUFS;
900cdfce9ceSjonathan 			}
901cdfce9ceSjonathan 
902cdfce9ceSjonathan 			for (k = 0; k < cri->cri_klen / 8; k++)
903cdfce9ceSjonathan 				cri->cri_key[k] ^= HMAC_IPAD_VAL;
904cdfce9ceSjonathan 
905cdfce9ceSjonathan 			axf->Init((*swd)->sw_ictx);
906cdfce9ceSjonathan 			axf->Update((*swd)->sw_ictx, cri->cri_key,
907cdfce9ceSjonathan 			    cri->cri_klen / 8);
908cdfce9ceSjonathan 			axf->Update((*swd)->sw_ictx, hmac_ipad_buffer,
909b4da53f1Sdrochner 			    axf->auth_hash->blocksize - (cri->cri_klen / 8));
910cdfce9ceSjonathan 
911cdfce9ceSjonathan 			for (k = 0; k < cri->cri_klen / 8; k++)
912cdfce9ceSjonathan 				cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
913cdfce9ceSjonathan 
914cdfce9ceSjonathan 			axf->Init((*swd)->sw_octx);
915cdfce9ceSjonathan 			axf->Update((*swd)->sw_octx, cri->cri_key,
916cdfce9ceSjonathan 			    cri->cri_klen / 8);
917cdfce9ceSjonathan 			axf->Update((*swd)->sw_octx, hmac_opad_buffer,
918b4da53f1Sdrochner 			    axf->auth_hash->blocksize - (cri->cri_klen / 8));
919cdfce9ceSjonathan 
920cdfce9ceSjonathan 			for (k = 0; k < cri->cri_klen / 8; k++)
921cdfce9ceSjonathan 				cri->cri_key[k] ^= HMAC_OPAD_VAL;
922cdfce9ceSjonathan 			(*swd)->sw_axf = axf;
923cdfce9ceSjonathan 			break;
924cdfce9ceSjonathan 
925cdfce9ceSjonathan 		case CRYPTO_MD5_KPDK:
9267bc6d90cSthorpej 			axf = &swcr_auth_hash_key_md5;
927cdfce9ceSjonathan 			goto auth2common;
928cdfce9ceSjonathan 
9297654585cSozaki-r 		case CRYPTO_SHA1_KPDK: {
9307654585cSozaki-r 			unsigned char digest[SHA1_DIGEST_LENGTH];
9317654585cSozaki-r 			CTASSERT(SHA1_DIGEST_LENGTH >= MD5_DIGEST_LENGTH);
9327bc6d90cSthorpej 			axf = &swcr_auth_hash_key_sha1;
933cdfce9ceSjonathan 		auth2common:
9348835ffd0Sriastradh 			(*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
935cdfce9ceSjonathan 			if ((*swd)->sw_ictx == NULL) {
936cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
937cdfce9ceSjonathan 				return ENOBUFS;
938cdfce9ceSjonathan 			}
939cdfce9ceSjonathan 
940cdfce9ceSjonathan 			/* Store the key so we can "append" it to the payload */
9418835ffd0Sriastradh 			(*swd)->sw_octx = kmem_alloc(cri->cri_klen / 8,
9428835ffd0Sriastradh 			    KM_NOSLEEP);
943cdfce9ceSjonathan 			if ((*swd)->sw_octx == NULL) {
944cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
945cdfce9ceSjonathan 				return ENOBUFS;
946cdfce9ceSjonathan 			}
947cdfce9ceSjonathan 
948cdfce9ceSjonathan 			(*swd)->sw_klen = cri->cri_klen / 8;
949e2cb8590Scegger 			memcpy((*swd)->sw_octx, cri->cri_key, cri->cri_klen / 8);
950cdfce9ceSjonathan 			axf->Init((*swd)->sw_ictx);
951cdfce9ceSjonathan 			axf->Update((*swd)->sw_ictx, cri->cri_key,
952cdfce9ceSjonathan 			    cri->cri_klen / 8);
9537654585cSozaki-r 			axf->Final(digest, (*swd)->sw_ictx);
954cdfce9ceSjonathan 			(*swd)->sw_axf = axf;
955cdfce9ceSjonathan 			break;
9567654585cSozaki-r 		    }
957cdfce9ceSjonathan 
958cdfce9ceSjonathan 		case CRYPTO_MD5:
9597bc6d90cSthorpej 			axf = &swcr_auth_hash_md5;
960cdfce9ceSjonathan 			goto auth3common;
961cdfce9ceSjonathan 
962cdfce9ceSjonathan 		case CRYPTO_SHA1:
9637bc6d90cSthorpej 			axf = &swcr_auth_hash_sha1;
964cdfce9ceSjonathan 		auth3common:
9658835ffd0Sriastradh 			(*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
966cdfce9ceSjonathan 			if ((*swd)->sw_ictx == NULL) {
967cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
968cdfce9ceSjonathan 				return ENOBUFS;
969cdfce9ceSjonathan 			}
970cdfce9ceSjonathan 
971cdfce9ceSjonathan 			axf->Init((*swd)->sw_ictx);
972cdfce9ceSjonathan 			(*swd)->sw_axf = axf;
973cdfce9ceSjonathan 			break;
974cdfce9ceSjonathan 
975ebc232a5Sdrochner 		case CRYPTO_AES_XCBC_MAC_96:
976ebc232a5Sdrochner 			axf = &swcr_auth_hash_aes_xcbc_mac;
9770a8dabdaSdrochner 			goto auth4common;
9780a8dabdaSdrochner 		case CRYPTO_AES_128_GMAC:
9790a8dabdaSdrochner 			axf = &swcr_auth_hash_gmac_aes_128;
9800a8dabdaSdrochner 			goto auth4common;
9810a8dabdaSdrochner 		case CRYPTO_AES_192_GMAC:
9820a8dabdaSdrochner 			axf = &swcr_auth_hash_gmac_aes_192;
9830a8dabdaSdrochner 			goto auth4common;
9840a8dabdaSdrochner 		case CRYPTO_AES_256_GMAC:
9850a8dabdaSdrochner 			axf = &swcr_auth_hash_gmac_aes_256;
9860a8dabdaSdrochner 		auth4common:
9878835ffd0Sriastradh 			(*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
988ebc232a5Sdrochner 			if ((*swd)->sw_ictx == NULL) {
989cfd5cbf4Sknakahara 				swcr_freesession_internal(first);
990ebc232a5Sdrochner 				return ENOBUFS;
991ebc232a5Sdrochner 			}
992ebc232a5Sdrochner 			axf->Init((*swd)->sw_ictx);
993ebc232a5Sdrochner 			axf->Setkey((*swd)->sw_ictx,
994ebc232a5Sdrochner 				cri->cri_key, cri->cri_klen / 8);
995ebc232a5Sdrochner 			(*swd)->sw_axf = axf;
996ebc232a5Sdrochner 			break;
997ebc232a5Sdrochner 
998cdfce9ceSjonathan 		case CRYPTO_DEFLATE_COMP:
9997bc6d90cSthorpej 			cxf = &swcr_comp_algo_deflate;
1000cdfce9ceSjonathan 			(*swd)->sw_cxf = cxf;
1001cdfce9ceSjonathan 			break;
100236ea3668Sdarran 
10031caa9a52Sdrochner 		case CRYPTO_DEFLATE_COMP_NOGROW:
10041caa9a52Sdrochner 			cxf = &swcr_comp_algo_deflate_nogrow;
10051caa9a52Sdrochner 			(*swd)->sw_cxf = cxf;
10061caa9a52Sdrochner 			break;
10071caa9a52Sdrochner 
100836ea3668Sdarran 		case CRYPTO_GZIP_COMP:
100936ea3668Sdarran 			cxf = &swcr_comp_algo_gzip;
101036ea3668Sdarran 			(*swd)->sw_cxf = cxf;
101136ea3668Sdarran 			break;
1012cdfce9ceSjonathan 		default:
1013cfd5cbf4Sknakahara 			swcr_freesession_internal(first);
1014cdfce9ceSjonathan 			return EINVAL;
1015cdfce9ceSjonathan 		}
1016cdfce9ceSjonathan 
1017cdfce9ceSjonathan 		(*swd)->sw_alg = cri->cri_alg;
1018cdfce9ceSjonathan 		cri = cri->cri_next;
1019cdfce9ceSjonathan 		swd = &((*swd)->sw_next);
1020cdfce9ceSjonathan 	}
1021cfd5cbf4Sknakahara 
1022cfd5cbf4Sknakahara 	swcr_sessions[i] = first;
1023cfd5cbf4Sknakahara 	*sid = i;
1024cdfce9ceSjonathan 	return 0;
1025cdfce9ceSjonathan }
1026cdfce9ceSjonathan 
1027cfd5cbf4Sknakahara static void
swcr_freesession_internal(struct swcr_data * arg)1028cfd5cbf4Sknakahara swcr_freesession_internal(struct swcr_data *arg)
1029cdfce9ceSjonathan {
1030cfd5cbf4Sknakahara 	struct swcr_data *swd, *swd0;
10317bc6d90cSthorpej 	const struct swcr_enc_xform *txf;
10327bc6d90cSthorpej 	const struct swcr_auth_hash *axf;
1033cdfce9ceSjonathan 
1034cfd5cbf4Sknakahara 	if (arg == NULL)
1035cfd5cbf4Sknakahara 		return;
1036cdfce9ceSjonathan 
1037cfd5cbf4Sknakahara 	swd0 = arg;
1038cfd5cbf4Sknakahara 	while ((swd = swd0) != NULL) {
1039cfd5cbf4Sknakahara 		swd0 = swd->sw_next;
1040cdfce9ceSjonathan 
1041cdfce9ceSjonathan 		switch (swd->sw_alg) {
1042cdfce9ceSjonathan 		case CRYPTO_DES_CBC:
1043cdfce9ceSjonathan 		case CRYPTO_3DES_CBC:
1044cdfce9ceSjonathan 		case CRYPTO_BLF_CBC:
1045cdfce9ceSjonathan 		case CRYPTO_CAST_CBC:
1046cdfce9ceSjonathan 		case CRYPTO_SKIPJACK_CBC:
10478835ffd0Sriastradh 		case CRYPTO_AES_CBC:
10483d2cef17Sdrochner 		case CRYPTO_CAMELLIA_CBC:
10493e66cf48Sdrochner 		case CRYPTO_AES_CTR:
10500a8dabdaSdrochner 		case CRYPTO_AES_GCM_16:
105149c12b7aSdrochner 		case CRYPTO_AES_GMAC:
1052cdfce9ceSjonathan 		case CRYPTO_NULL_CBC:
1053cdfce9ceSjonathan 			txf = swd->sw_exf;
1054cdfce9ceSjonathan 
1055cdfce9ceSjonathan 			if (swd->sw_kschedule)
1056cdfce9ceSjonathan 				txf->zerokey(&(swd->sw_kschedule));
1057cdfce9ceSjonathan 			break;
1058cdfce9ceSjonathan 
1059cdfce9ceSjonathan 		case CRYPTO_MD5_HMAC:
1060e2205fa0Stls 		case CRYPTO_MD5_HMAC_96:
1061cdfce9ceSjonathan 		case CRYPTO_SHA1_HMAC:
1062e2205fa0Stls 		case CRYPTO_SHA1_HMAC_96:
1063b4da53f1Sdrochner 		case CRYPTO_SHA2_256_HMAC:
1064b4da53f1Sdrochner 		case CRYPTO_SHA2_384_HMAC:
1065b4da53f1Sdrochner 		case CRYPTO_SHA2_512_HMAC:
1066cdfce9ceSjonathan 		case CRYPTO_RIPEMD160_HMAC:
1067e2205fa0Stls 		case CRYPTO_RIPEMD160_HMAC_96:
1068cdfce9ceSjonathan 		case CRYPTO_NULL_HMAC:
1069cdfce9ceSjonathan 			axf = swd->sw_axf;
1070cdfce9ceSjonathan 
1071cdfce9ceSjonathan 			if (swd->sw_ictx) {
107282db4b98Sriastradh 				explicit_memset(swd->sw_ictx, 0, axf->ctxsize);
10738835ffd0Sriastradh 				kmem_free(swd->sw_ictx, axf->ctxsize);
1074cdfce9ceSjonathan 			}
1075cdfce9ceSjonathan 			if (swd->sw_octx) {
107682db4b98Sriastradh 				explicit_memset(swd->sw_octx, 0, axf->ctxsize);
10778835ffd0Sriastradh 				kmem_free(swd->sw_octx, axf->ctxsize);
1078cdfce9ceSjonathan 			}
1079cdfce9ceSjonathan 			break;
1080cdfce9ceSjonathan 
1081cdfce9ceSjonathan 		case CRYPTO_MD5_KPDK:
1082cdfce9ceSjonathan 		case CRYPTO_SHA1_KPDK:
1083cdfce9ceSjonathan 			axf = swd->sw_axf;
1084cdfce9ceSjonathan 
1085cdfce9ceSjonathan 			if (swd->sw_ictx) {
108682db4b98Sriastradh 				explicit_memset(swd->sw_ictx, 0, axf->ctxsize);
10878835ffd0Sriastradh 				kmem_free(swd->sw_ictx, axf->ctxsize);
1088cdfce9ceSjonathan 			}
1089cdfce9ceSjonathan 			if (swd->sw_octx) {
109082db4b98Sriastradh 				explicit_memset(swd->sw_octx, 0, swd->sw_klen);
10915da7826cSriastradh 				kmem_free(swd->sw_octx, swd->sw_klen);
1092cdfce9ceSjonathan 			}
1093cdfce9ceSjonathan 			break;
1094cdfce9ceSjonathan 
1095cdfce9ceSjonathan 		case CRYPTO_MD5:
1096cdfce9ceSjonathan 		case CRYPTO_SHA1:
1097ebc232a5Sdrochner 		case CRYPTO_AES_XCBC_MAC_96:
10980a8dabdaSdrochner 		case CRYPTO_AES_128_GMAC:
10990a8dabdaSdrochner 		case CRYPTO_AES_192_GMAC:
11000a8dabdaSdrochner 		case CRYPTO_AES_256_GMAC:
1101cdfce9ceSjonathan 			axf = swd->sw_axf;
1102cdfce9ceSjonathan 
11038588929dSdrochner 			if (swd->sw_ictx) {
110482db4b98Sriastradh 				explicit_memset(swd->sw_ictx, 0, axf->ctxsize);
11058835ffd0Sriastradh 				kmem_free(swd->sw_ictx, axf->ctxsize);
11068588929dSdrochner 			}
1107cdfce9ceSjonathan 			break;
1108cdfce9ceSjonathan 
1109cdfce9ceSjonathan 		case CRYPTO_DEFLATE_COMP:
11101caa9a52Sdrochner 		case CRYPTO_DEFLATE_COMP_NOGROW:
111136ea3668Sdarran 		case CRYPTO_GZIP_COMP:
1112cdfce9ceSjonathan 			break;
1113cdfce9ceSjonathan 		}
1114cdfce9ceSjonathan 
11155b59f58dSknakahara 		kmem_free(swd, sizeof(*swd));
1116cdfce9ceSjonathan 	}
1117cfd5cbf4Sknakahara }
1118cfd5cbf4Sknakahara 
1119cfd5cbf4Sknakahara /*
1120cfd5cbf4Sknakahara  * Free a session.
1121cfd5cbf4Sknakahara  */
1122*ee55792fSriastradh static void
swcr_freesession(void * arg,u_int64_t tid)1123cfd5cbf4Sknakahara swcr_freesession(void *arg, u_int64_t tid)
1124cfd5cbf4Sknakahara {
1125cfd5cbf4Sknakahara 	struct swcr_data *swd;
1126cfd5cbf4Sknakahara 	u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
1127cfd5cbf4Sknakahara 
1128486d5a49Sriastradh 	KASSERTMSG(sid < swcr_sesnum, "sid=%"PRIu32" swcr_sesnum=%"PRIu32,
1129486d5a49Sriastradh 	    sid, swcr_sesnum);
1130486d5a49Sriastradh 	KASSERT(swcr_sessions[sid]);
1131cfd5cbf4Sknakahara 
1132cfd5cbf4Sknakahara 	swd = swcr_sessions[sid];
1133cfd5cbf4Sknakahara 	swcr_sessions[sid] = NULL;
1134cfd5cbf4Sknakahara 	swcr_freesession_internal(swd);
1135cdfce9ceSjonathan }
1136cdfce9ceSjonathan 
1137cdfce9ceSjonathan /*
1138cdfce9ceSjonathan  * Process a software request.
1139cdfce9ceSjonathan  */
1140cdfce9ceSjonathan static int
swcr_process(void * arg,struct cryptop * crp,int hint)1141168cd830Schristos swcr_process(void *arg, struct cryptop *crp, int hint)
1142cdfce9ceSjonathan {
1143cdfce9ceSjonathan 	struct cryptodesc *crd;
1144cdfce9ceSjonathan 	struct swcr_data *sw;
1145cdfce9ceSjonathan 	u_int32_t lid;
1146cdfce9ceSjonathan 	int type;
1147cdfce9ceSjonathan 
1148cdfce9ceSjonathan 	/* Sanity check */
1149cdfce9ceSjonathan 	if (crp == NULL)
1150cdfce9ceSjonathan 		return EINVAL;
1151cdfce9ceSjonathan 
1152cdfce9ceSjonathan 	if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
1153cdfce9ceSjonathan 		crp->crp_etype = EINVAL;
1154cdfce9ceSjonathan 		goto done;
1155cdfce9ceSjonathan 	}
1156cdfce9ceSjonathan 
1157cdfce9ceSjonathan 	lid = crp->crp_sid & 0xffffffff;
1158cdfce9ceSjonathan 	if (lid >= swcr_sesnum || lid == 0 || swcr_sessions[lid] == NULL) {
1159cdfce9ceSjonathan 		crp->crp_etype = ENOENT;
1160cdfce9ceSjonathan 		goto done;
1161cdfce9ceSjonathan 	}
1162cdfce9ceSjonathan 
1163cdfce9ceSjonathan 	if (crp->crp_flags & CRYPTO_F_IMBUF) {
1164cdfce9ceSjonathan 		type = CRYPTO_BUF_MBUF;
1165cdfce9ceSjonathan 	} else if (crp->crp_flags & CRYPTO_F_IOV) {
1166cdfce9ceSjonathan 		type = CRYPTO_BUF_IOV;
1167cdfce9ceSjonathan 	} else {
1168cdfce9ceSjonathan 		type = CRYPTO_BUF_CONTIG;
1169cdfce9ceSjonathan 	}
1170cdfce9ceSjonathan 
1171cdfce9ceSjonathan 	/* Go through crypto descriptors, processing as we go */
1172cdfce9ceSjonathan 	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
1173cdfce9ceSjonathan 		/*
1174cdfce9ceSjonathan 		 * Find the crypto context.
1175cdfce9ceSjonathan 		 *
1176cdfce9ceSjonathan 		 * XXX Note that the logic here prevents us from having
1177cdfce9ceSjonathan 		 * XXX the same algorithm multiple times in a session
1178cdfce9ceSjonathan 		 * XXX (or rather, we can but it won't give us the right
1179cdfce9ceSjonathan 		 * XXX results). To do that, we'd need some way of differentiating
1180cdfce9ceSjonathan 		 * XXX between the various instances of an algorithm (so we can
1181cdfce9ceSjonathan 		 * XXX locate the correct crypto context).
1182cdfce9ceSjonathan 		 */
1183cdfce9ceSjonathan 		for (sw = swcr_sessions[lid];
1184cdfce9ceSjonathan 		    sw && sw->sw_alg != crd->crd_alg;
1185cdfce9ceSjonathan 		    sw = sw->sw_next)
1186cdfce9ceSjonathan 			;
1187cdfce9ceSjonathan 
1188cdfce9ceSjonathan 		/* No such context ? */
1189cdfce9ceSjonathan 		if (sw == NULL) {
1190cdfce9ceSjonathan 			crp->crp_etype = EINVAL;
1191cdfce9ceSjonathan 			goto done;
1192cdfce9ceSjonathan 		}
1193cdfce9ceSjonathan 
1194cdfce9ceSjonathan 		switch (sw->sw_alg) {
1195cdfce9ceSjonathan 		case CRYPTO_DES_CBC:
1196cdfce9ceSjonathan 		case CRYPTO_3DES_CBC:
1197cdfce9ceSjonathan 		case CRYPTO_BLF_CBC:
1198cdfce9ceSjonathan 		case CRYPTO_CAST_CBC:
1199cdfce9ceSjonathan 		case CRYPTO_SKIPJACK_CBC:
12008835ffd0Sriastradh 		case CRYPTO_AES_CBC:
12013d2cef17Sdrochner 		case CRYPTO_CAMELLIA_CBC:
12023e66cf48Sdrochner 		case CRYPTO_AES_CTR:
1203cdfce9ceSjonathan 			if ((crp->crp_etype = swcr_encdec(crd, sw,
1204cdfce9ceSjonathan 			    crp->crp_buf, type)) != 0)
1205cdfce9ceSjonathan 				goto done;
1206cdfce9ceSjonathan 			break;
1207cdfce9ceSjonathan 		case CRYPTO_NULL_CBC:
1208cdfce9ceSjonathan 			crp->crp_etype = 0;
1209cdfce9ceSjonathan 			break;
1210cdfce9ceSjonathan 		case CRYPTO_MD5_HMAC:
1211e2205fa0Stls 		case CRYPTO_MD5_HMAC_96:
1212cdfce9ceSjonathan 		case CRYPTO_SHA1_HMAC:
1213e2205fa0Stls 		case CRYPTO_SHA1_HMAC_96:
1214b4da53f1Sdrochner 		case CRYPTO_SHA2_256_HMAC:
1215b4da53f1Sdrochner 		case CRYPTO_SHA2_384_HMAC:
1216b4da53f1Sdrochner 		case CRYPTO_SHA2_512_HMAC:
1217cdfce9ceSjonathan 		case CRYPTO_RIPEMD160_HMAC:
1218e2205fa0Stls 		case CRYPTO_RIPEMD160_HMAC_96:
1219cdfce9ceSjonathan 		case CRYPTO_NULL_HMAC:
1220cdfce9ceSjonathan 		case CRYPTO_MD5_KPDK:
1221cdfce9ceSjonathan 		case CRYPTO_SHA1_KPDK:
1222cdfce9ceSjonathan 		case CRYPTO_MD5:
1223cdfce9ceSjonathan 		case CRYPTO_SHA1:
1224ebc232a5Sdrochner 		case CRYPTO_AES_XCBC_MAC_96:
1225cdfce9ceSjonathan 			if ((crp->crp_etype = swcr_authcompute(crp, crd, sw,
1226cdfce9ceSjonathan 			    crp->crp_buf, type)) != 0)
1227cdfce9ceSjonathan 				goto done;
1228cdfce9ceSjonathan 			break;
1229cdfce9ceSjonathan 
12300a8dabdaSdrochner 		case CRYPTO_AES_GCM_16:
12310a8dabdaSdrochner 		case CRYPTO_AES_GMAC:
12320a8dabdaSdrochner 		case CRYPTO_AES_128_GMAC:
12330a8dabdaSdrochner 		case CRYPTO_AES_192_GMAC:
12340a8dabdaSdrochner 		case CRYPTO_AES_256_GMAC:
12350a8dabdaSdrochner 			crp->crp_etype = swcr_combined(crp, type);
12360a8dabdaSdrochner 			goto done;
12370a8dabdaSdrochner 
1238cdfce9ceSjonathan 		case CRYPTO_DEFLATE_COMP:
12391caa9a52Sdrochner 		case CRYPTO_DEFLATE_COMP_NOGROW:
124036ea3668Sdarran 		case CRYPTO_GZIP_COMP:
1241c4e549c7Sknakahara 			DPRINTF("compdec for %d\n", sw->sw_alg);
1242cdfce9ceSjonathan 			if ((crp->crp_etype = swcr_compdec(crd, sw,
12432e4e5505Sdrochner 			    crp->crp_buf, type, &crp->crp_olen)) != 0)
1244cdfce9ceSjonathan 				goto done;
1245cdfce9ceSjonathan 			break;
1246cdfce9ceSjonathan 
1247cdfce9ceSjonathan 		default:
1248cdfce9ceSjonathan 			/* Unknown/unsupported algorithm */
1249cdfce9ceSjonathan 			crp->crp_etype = EINVAL;
1250cdfce9ceSjonathan 			goto done;
1251cdfce9ceSjonathan 		}
1252cdfce9ceSjonathan 	}
1253cdfce9ceSjonathan 
1254cdfce9ceSjonathan done:
1255c4e549c7Sknakahara 	DPRINTF("request %p done\n", crp);
1256cdfce9ceSjonathan 	crypto_done(crp);
1257cdfce9ceSjonathan 	return 0;
1258cdfce9ceSjonathan }
1259cdfce9ceSjonathan 
12607bc6d90cSthorpej static void
swcr_init(void)1261cdfce9ceSjonathan swcr_init(void)
1262cdfce9ceSjonathan {
1263cdfce9ceSjonathan 	swcr_id = crypto_get_driverid(CRYPTOCAP_F_SOFTWARE);
1264cdfce9ceSjonathan 	if (swcr_id < 0) {
1265cdfce9ceSjonathan 		/* This should never happen */
1266cdfce9ceSjonathan 		panic("Software crypto device cannot initialize!");
1267cdfce9ceSjonathan 	}
1268cdfce9ceSjonathan 
1269cdfce9ceSjonathan 	crypto_register(swcr_id, CRYPTO_DES_CBC,
1270cdfce9ceSjonathan 	    0, 0, swcr_newsession, swcr_freesession, swcr_process, NULL);
1271cdfce9ceSjonathan #define	REGISTER(alg) \
1272cdfce9ceSjonathan 	crypto_register(swcr_id, alg, 0, 0, NULL, NULL, NULL, NULL)
1273cdfce9ceSjonathan 
1274cdfce9ceSjonathan 	REGISTER(CRYPTO_3DES_CBC);
1275cdfce9ceSjonathan 	REGISTER(CRYPTO_BLF_CBC);
1276cdfce9ceSjonathan 	REGISTER(CRYPTO_CAST_CBC);
1277cdfce9ceSjonathan 	REGISTER(CRYPTO_SKIPJACK_CBC);
12783d2cef17Sdrochner 	REGISTER(CRYPTO_CAMELLIA_CBC);
12793e66cf48Sdrochner 	REGISTER(CRYPTO_AES_CTR);
12800a8dabdaSdrochner 	REGISTER(CRYPTO_AES_GCM_16);
12810a8dabdaSdrochner 	REGISTER(CRYPTO_AES_GMAC);
1282cdfce9ceSjonathan 	REGISTER(CRYPTO_NULL_CBC);
1283cdfce9ceSjonathan 	REGISTER(CRYPTO_MD5_HMAC);
1284e2205fa0Stls 	REGISTER(CRYPTO_MD5_HMAC_96);
1285cdfce9ceSjonathan 	REGISTER(CRYPTO_SHA1_HMAC);
1286e2205fa0Stls 	REGISTER(CRYPTO_SHA1_HMAC_96);
1287b4da53f1Sdrochner 	REGISTER(CRYPTO_SHA2_256_HMAC);
1288b4da53f1Sdrochner 	REGISTER(CRYPTO_SHA2_384_HMAC);
1289b4da53f1Sdrochner 	REGISTER(CRYPTO_SHA2_512_HMAC);
1290cdfce9ceSjonathan 	REGISTER(CRYPTO_RIPEMD160_HMAC);
1291e2205fa0Stls 	REGISTER(CRYPTO_RIPEMD160_HMAC_96);
1292cdfce9ceSjonathan 	REGISTER(CRYPTO_NULL_HMAC);
1293cdfce9ceSjonathan 	REGISTER(CRYPTO_MD5_KPDK);
1294cdfce9ceSjonathan 	REGISTER(CRYPTO_SHA1_KPDK);
1295cdfce9ceSjonathan 	REGISTER(CRYPTO_MD5);
1296cdfce9ceSjonathan 	REGISTER(CRYPTO_SHA1);
1297ebc232a5Sdrochner 	REGISTER(CRYPTO_AES_XCBC_MAC_96);
12980a8dabdaSdrochner 	REGISTER(CRYPTO_AES_128_GMAC);
12990a8dabdaSdrochner 	REGISTER(CRYPTO_AES_192_GMAC);
13000a8dabdaSdrochner 	REGISTER(CRYPTO_AES_256_GMAC);
13018835ffd0Sriastradh 	REGISTER(CRYPTO_AES_CBC);
1302cdfce9ceSjonathan 	REGISTER(CRYPTO_DEFLATE_COMP);
13031caa9a52Sdrochner 	REGISTER(CRYPTO_DEFLATE_COMP_NOGROW);
130436ea3668Sdarran 	REGISTER(CRYPTO_GZIP_COMP);
1305cdfce9ceSjonathan #undef REGISTER
1306cdfce9ceSjonathan }
1307cdfce9ceSjonathan 
13087bc6d90cSthorpej 
13097bc6d90cSthorpej /*
13107bc6d90cSthorpej  * Pseudo-device init routine for software crypto.
13117bc6d90cSthorpej  */
13127bc6d90cSthorpej 
13137bc6d90cSthorpej void
swcryptoattach(int num)1314168cd830Schristos swcryptoattach(int num)
13157bc6d90cSthorpej {
1316993fdeecSknakahara 	/*
131780c73109Sknakahara 	 * swcrypto_attach() must be called after attached cpus, because
131880c73109Sknakahara 	 * it calls softint_establish() through below call path.
131980c73109Sknakahara 	 *     swcr_init() => crypto_get_driverid() => crypto_init()
132080c73109Sknakahara 	 *         => crypto_init0()
132180c73109Sknakahara 	 * If softint_establish() is called before attached cpus that ncpu == 0,
132280c73109Sknakahara 	 * the softint handler is established to CPU#0 only.
132380c73109Sknakahara 	 *
132480c73109Sknakahara 	 * So, swcrypto_attach() must be called from not module_init_class()
132580c73109Sknakahara 	 * but config_finalize() when it is built as builtin module.
1326993fdeecSknakahara 	 */
132780c73109Sknakahara 	swcryptoattach_internal();
13287bc6d90cSthorpej }
13292dd4f4d9Spgoyette 
13302dd4f4d9Spgoyette void	swcrypto_attach(device_t, device_t, void *);
13312dd4f4d9Spgoyette 
13322dd4f4d9Spgoyette void
swcrypto_attach(device_t parent,device_t self,void * opaque)13332dd4f4d9Spgoyette swcrypto_attach(device_t parent, device_t self, void *opaque)
13342dd4f4d9Spgoyette {
13352dd4f4d9Spgoyette 
13362dd4f4d9Spgoyette 	swcr_init();
1337f43f371eSchristos 
1338f43f371eSchristos 	if (!pmf_device_register(self, NULL, NULL))
1339f43f371eSchristos 		aprint_error_dev(self, "couldn't establish power handler\n");
13402dd4f4d9Spgoyette }
13412dd4f4d9Spgoyette 
13422dd4f4d9Spgoyette int	swcrypto_detach(device_t, int);
13432dd4f4d9Spgoyette 
13442dd4f4d9Spgoyette int
swcrypto_detach(device_t self,int flag)13452dd4f4d9Spgoyette swcrypto_detach(device_t self, int flag)
13462dd4f4d9Spgoyette {
1347f1257be5Sriastradh 	pmf_device_deregister(self);
13482dd4f4d9Spgoyette 	if (swcr_id >= 0)
13492dd4f4d9Spgoyette 		crypto_unregister_all(swcr_id);
13502dd4f4d9Spgoyette 	return 0;
13512dd4f4d9Spgoyette }
13522dd4f4d9Spgoyette 
13532dd4f4d9Spgoyette int	swcrypto_match(device_t, cfdata_t, void *);
13542dd4f4d9Spgoyette 
13552dd4f4d9Spgoyette int
swcrypto_match(device_t parent,cfdata_t data,void * opaque)13562dd4f4d9Spgoyette swcrypto_match(device_t parent, cfdata_t data, void *opaque)
13572dd4f4d9Spgoyette {
13582dd4f4d9Spgoyette 
13592dd4f4d9Spgoyette         return 1;
13602dd4f4d9Spgoyette }
13612dd4f4d9Spgoyette 
13622dd4f4d9Spgoyette MODULE(MODULE_CLASS_DRIVER, swcrypto,
13632dd4f4d9Spgoyette 	"opencrypto,zlib,blowfish,des,cast128,camellia,skipjack");
13642dd4f4d9Spgoyette 
13652dd4f4d9Spgoyette CFDRIVER_DECL(swcrypto, DV_DULL, NULL);
13662dd4f4d9Spgoyette 
13672dd4f4d9Spgoyette CFATTACH_DECL2_NEW(swcrypto, 0, swcrypto_match, swcrypto_attach,
13682dd4f4d9Spgoyette     swcrypto_detach, NULL, NULL, NULL);
13692dd4f4d9Spgoyette 
13702dd4f4d9Spgoyette static int swcryptoloc[] = { -1, -1 };
13712dd4f4d9Spgoyette 
13722dd4f4d9Spgoyette static struct cfdata swcrypto_cfdata[] = {
13732dd4f4d9Spgoyette 	{
13742dd4f4d9Spgoyette 		.cf_name = "swcrypto",
13752dd4f4d9Spgoyette 		.cf_atname = "swcrypto",
13762dd4f4d9Spgoyette 		.cf_unit = 0,
13772dd4f4d9Spgoyette 		.cf_fstate = 0,
13782dd4f4d9Spgoyette 		.cf_loc = swcryptoloc,
13792dd4f4d9Spgoyette 		.cf_flags = 0,
13802dd4f4d9Spgoyette 		.cf_pspec = NULL,
13812dd4f4d9Spgoyette 	},
13822dd4f4d9Spgoyette 	{ NULL, NULL, 0, 0, NULL, 0, NULL }
13832dd4f4d9Spgoyette };
13842dd4f4d9Spgoyette 
138580c73109Sknakahara /*
138680c73109Sknakahara  * Internal attach routine.
138780c73109Sknakahara  * Don't call before attached cpus.
138880c73109Sknakahara  */
13892dd4f4d9Spgoyette static int
swcryptoattach_internal(void)139080c73109Sknakahara swcryptoattach_internal(void)
13912dd4f4d9Spgoyette {
13922dd4f4d9Spgoyette 	int error;
13932dd4f4d9Spgoyette 
13942dd4f4d9Spgoyette 	error = config_cfdriver_attach(&swcrypto_cd);
13952dd4f4d9Spgoyette 	if (error) {
13962dd4f4d9Spgoyette 		return error;
13972dd4f4d9Spgoyette 	}
13982dd4f4d9Spgoyette 
139980c73109Sknakahara 	error = config_cfattach_attach(swcrypto_cd.cd_name, &swcrypto_ca);
14002dd4f4d9Spgoyette 	if (error) {
14012dd4f4d9Spgoyette 		config_cfdriver_detach(&swcrypto_cd);
14022dd4f4d9Spgoyette 		aprint_error("%s: unable to register cfattach\n",
14032dd4f4d9Spgoyette 		    swcrypto_cd.cd_name);
14042dd4f4d9Spgoyette 
14052dd4f4d9Spgoyette 		return error;
14062dd4f4d9Spgoyette 	}
14072dd4f4d9Spgoyette 
14082dd4f4d9Spgoyette 	error = config_cfdata_attach(swcrypto_cfdata, 1);
14092dd4f4d9Spgoyette 	if (error) {
14102dd4f4d9Spgoyette 		config_cfattach_detach(swcrypto_cd.cd_name,
14112dd4f4d9Spgoyette 		    &swcrypto_ca);
14122dd4f4d9Spgoyette 		config_cfdriver_detach(&swcrypto_cd);
14132dd4f4d9Spgoyette 		aprint_error("%s: unable to register cfdata\n",
14142dd4f4d9Spgoyette 		    swcrypto_cd.cd_name);
14152dd4f4d9Spgoyette 
14162dd4f4d9Spgoyette 		return error;
14172dd4f4d9Spgoyette 	}
14182dd4f4d9Spgoyette 
14192dd4f4d9Spgoyette 	(void)config_attach_pseudo(swcrypto_cfdata);
14202dd4f4d9Spgoyette 
14212dd4f4d9Spgoyette 	return 0;
142280c73109Sknakahara }
142380c73109Sknakahara 
142480c73109Sknakahara static int
swcrypto_modcmd(modcmd_t cmd,void * arg)142580c73109Sknakahara swcrypto_modcmd(modcmd_t cmd, void *arg)
142680c73109Sknakahara {
142780c73109Sknakahara 	int error = 0;
142880c73109Sknakahara 
142980c73109Sknakahara 	switch (cmd) {
143080c73109Sknakahara 	case MODULE_CMD_INIT:
143180c73109Sknakahara #ifdef _MODULE
143280c73109Sknakahara 		error = swcryptoattach_internal();
143380c73109Sknakahara #endif
143480c73109Sknakahara 		return error;
14352dd4f4d9Spgoyette 	case MODULE_CMD_FINI:
1436d40a55d1Schristos #if 1
1437d40a55d1Schristos 		// XXX: Need to keep track if we are in use.
1438d40a55d1Schristos 		return ENOTTY;
1439d40a55d1Schristos #else
14402dd4f4d9Spgoyette 		error = config_cfdata_detach(swcrypto_cfdata);
14412dd4f4d9Spgoyette 		if (error) {
14422dd4f4d9Spgoyette 			return error;
14432dd4f4d9Spgoyette 		}
14442dd4f4d9Spgoyette 
14452dd4f4d9Spgoyette 		config_cfattach_detach(swcrypto_cd.cd_name, &swcrypto_ca);
14462dd4f4d9Spgoyette 		config_cfdriver_detach(&swcrypto_cd);
14472dd4f4d9Spgoyette 
14482dd4f4d9Spgoyette 		return 0;
1449d40a55d1Schristos #endif
14502dd4f4d9Spgoyette 	default:
14512dd4f4d9Spgoyette 		return ENOTTY;
14522dd4f4d9Spgoyette 	}
14532dd4f4d9Spgoyette }
1454