cryptodev.c revision 121256
1/*	$OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $	*/
2
3/*
4 * Copyright (c) 2001 Theo de Raadt
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *   notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *   derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Effort sponsored in part by the Defense Advanced Research Projects
30 * Agency (DARPA) and Air Force Research Laboratory, Air Force
31 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/opencrypto/cryptodev.c 121256 2003-10-19 20:41:07Z dwmalone $");
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/mbuf.h>
41#include <sys/lock.h>
42#include <sys/mutex.h>
43#include <sys/sysctl.h>
44#include <sys/file.h>
45#include <sys/filedesc.h>
46#include <sys/errno.h>
47#include <sys/uio.h>
48#include <sys/random.h>
49#include <sys/conf.h>
50#include <sys/kernel.h>
51#include <sys/fcntl.h>
52
53#include <opencrypto/cryptodev.h>
54#include <opencrypto/xform.h>
55
56struct csession {
57	TAILQ_ENTRY(csession) next;
58	u_int64_t	sid;
59	u_int32_t	ses;
60	struct mtx	lock;		/* for op submission */
61
62	u_int32_t	cipher;
63	struct enc_xform *txform;
64	u_int32_t	mac;
65	struct auth_hash *thash;
66
67	caddr_t		key;
68	int		keylen;
69	u_char		tmp_iv[EALG_MAX_BLOCK_LEN];
70
71	caddr_t		mackey;
72	int		mackeylen;
73	u_char		tmp_mac[CRYPTO_MAX_MAC_LEN];
74
75	struct iovec	iovec[UIO_MAXIOV];
76	struct uio	uio;
77	int		error;
78};
79
80struct fcrypt {
81	TAILQ_HEAD(csessionlist, csession) csessions;
82	int		sesn;
83};
84
85static	int cryptof_rw(struct file *fp, struct uio *uio,
86		    struct ucred *cred, int flags, struct thread *);
87static	int cryptof_ioctl(struct file *, u_long, void *,
88		    struct ucred *, struct thread *);
89static	int cryptof_poll(struct file *, int, struct ucred *, struct thread *);
90static	int cryptof_kqfilter(struct file *, struct knote *);
91static	int cryptof_stat(struct file *, struct stat *,
92		    struct ucred *, struct thread *);
93static	int cryptof_close(struct file *, struct thread *);
94
95static struct fileops cryptofops = {
96    .fo_read = cryptof_rw,
97    .fo_write = cryptof_rw,
98    .fo_ioctl = cryptof_ioctl,
99    .fo_poll = cryptof_poll,
100    .fo_kqfilter = cryptof_kqfilter,
101    .fo_stat = cryptof_stat,
102    .fo_close = cryptof_close
103};
104
105static struct csession *csefind(struct fcrypt *, u_int);
106static int csedelete(struct fcrypt *, struct csession *);
107static struct csession *cseadd(struct fcrypt *, struct csession *);
108static struct csession *csecreate(struct fcrypt *, u_int64_t, caddr_t,
109    u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *,
110    struct auth_hash *);
111static int csefree(struct csession *);
112
113static	int cryptodev_op(struct csession *, struct crypt_op *,
114			struct ucred *, struct thread *td);
115static	int cryptodev_key(struct crypt_kop *);
116
117static int
118cryptof_rw(
119	struct file *fp,
120	struct uio *uio,
121	struct ucred *active_cred,
122	int flags,
123	struct thread *td)
124{
125
126	return (EIO);
127}
128
129/* ARGSUSED */
130static int
131cryptof_ioctl(
132	struct file *fp,
133	u_long cmd,
134	void *data,
135	struct ucred *active_cred,
136	struct thread *td)
137{
138	struct cryptoini cria, crie;
139	struct fcrypt *fcr = fp->f_data;
140	struct csession *cse;
141	struct session_op *sop;
142	struct crypt_op *cop;
143	struct enc_xform *txform = NULL;
144	struct auth_hash *thash = NULL;
145	u_int64_t sid;
146	u_int32_t ses;
147	int error = 0;
148
149	switch (cmd) {
150	case CIOCGSESSION:
151		sop = (struct session_op *)data;
152		switch (sop->cipher) {
153		case 0:
154			break;
155		case CRYPTO_DES_CBC:
156			txform = &enc_xform_des;
157			break;
158		case CRYPTO_3DES_CBC:
159			txform = &enc_xform_3des;
160			break;
161		case CRYPTO_BLF_CBC:
162			txform = &enc_xform_blf;
163			break;
164		case CRYPTO_CAST_CBC:
165			txform = &enc_xform_cast5;
166			break;
167		case CRYPTO_SKIPJACK_CBC:
168			txform = &enc_xform_skipjack;
169			break;
170		case CRYPTO_AES_CBC:
171			txform = &enc_xform_rijndael128;
172			break;
173		case CRYPTO_NULL_CBC:
174			txform = &enc_xform_null;
175			break;
176		case CRYPTO_ARC4:
177			txform = &enc_xform_arc4;
178			break;
179		default:
180			return (EINVAL);
181		}
182
183		switch (sop->mac) {
184		case 0:
185			break;
186		case CRYPTO_MD5_HMAC:
187			thash = &auth_hash_hmac_md5_96;
188			break;
189		case CRYPTO_SHA1_HMAC:
190			thash = &auth_hash_hmac_sha1_96;
191			break;
192		case CRYPTO_SHA2_HMAC:
193			if (sop->mackeylen == auth_hash_hmac_sha2_256.keysize)
194				thash = &auth_hash_hmac_sha2_256;
195			else if (sop->mackeylen == auth_hash_hmac_sha2_384.keysize)
196				thash = &auth_hash_hmac_sha2_384;
197			else if (sop->mackeylen == auth_hash_hmac_sha2_512.keysize)
198				thash = &auth_hash_hmac_sha2_512;
199			else
200				return (EINVAL);
201			break;
202		case CRYPTO_RIPEMD160_HMAC:
203			thash = &auth_hash_hmac_ripemd_160_96;
204			break;
205#ifdef notdef
206		case CRYPTO_MD5:
207			thash = &auth_hash_md5;
208			break;
209		case CRYPTO_SHA1:
210			thash = &auth_hash_sha1;
211			break;
212#endif
213		case CRYPTO_NULL_HMAC:
214			thash = &auth_hash_null;
215			break;
216		default:
217			return (EINVAL);
218		}
219
220		bzero(&crie, sizeof(crie));
221		bzero(&cria, sizeof(cria));
222
223		if (txform) {
224			crie.cri_alg = txform->type;
225			crie.cri_klen = sop->keylen * 8;
226			if (sop->keylen > txform->maxkey ||
227			    sop->keylen < txform->minkey) {
228				error = EINVAL;
229				goto bail;
230			}
231
232			MALLOC(crie.cri_key, u_int8_t *,
233			    crie.cri_klen / 8, M_XDATA, M_WAITOK);
234			if ((error = copyin(sop->key, crie.cri_key,
235			    crie.cri_klen / 8)))
236				goto bail;
237			if (thash)
238				crie.cri_next = &cria;
239		}
240
241		if (thash) {
242			cria.cri_alg = thash->type;
243			cria.cri_klen = sop->mackeylen * 8;
244			if (sop->mackeylen != thash->keysize) {
245				error = EINVAL;
246				goto bail;
247			}
248
249			if (cria.cri_klen) {
250				MALLOC(cria.cri_key, u_int8_t *,
251				    cria.cri_klen / 8, M_XDATA, M_WAITOK);
252				if ((error = copyin(sop->mackey, cria.cri_key,
253				    cria.cri_klen / 8)))
254					goto bail;
255			}
256		}
257
258		error = crypto_newsession(&sid, (txform ? &crie : &cria), 1);
259		if (error)
260			goto bail;
261
262		cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen,
263		    cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform,
264		    thash);
265
266		if (cse == NULL) {
267			crypto_freesession(sid);
268			error = EINVAL;
269			goto bail;
270		}
271		sop->ses = cse->ses;
272
273bail:
274		if (error) {
275			if (crie.cri_key)
276				FREE(crie.cri_key, M_XDATA);
277			if (cria.cri_key)
278				FREE(cria.cri_key, M_XDATA);
279		}
280		break;
281	case CIOCFSESSION:
282		ses = *(u_int32_t *)data;
283		cse = csefind(fcr, ses);
284		if (cse == NULL)
285			return (EINVAL);
286		csedelete(fcr, cse);
287		error = csefree(cse);
288		break;
289	case CIOCCRYPT:
290		cop = (struct crypt_op *)data;
291		cse = csefind(fcr, cop->ses);
292		if (cse == NULL)
293			return (EINVAL);
294		error = cryptodev_op(cse, cop, active_cred, td);
295		break;
296	case CIOCKEY:
297		error = cryptodev_key((struct crypt_kop *)data);
298		break;
299	case CIOCASYMFEAT:
300		error = crypto_getfeat((int *)data);
301		break;
302	default:
303		error = EINVAL;
304	}
305	return (error);
306}
307
308static int cryptodev_cb(void *);
309
310
311static int
312cryptodev_op(
313	struct csession *cse,
314	struct crypt_op *cop,
315	struct ucred *active_cred,
316	struct thread *td)
317{
318	struct cryptop *crp = NULL;
319	struct cryptodesc *crde = NULL, *crda = NULL;
320	int i, error;
321
322	if (cop->len > 256*1024-4)
323		return (E2BIG);
324
325	if (cse->txform && (cop->len % cse->txform->blocksize) != 0)
326		return (EINVAL);
327
328	bzero(&cse->uio, sizeof(cse->uio));
329	cse->uio.uio_iovcnt = 1;
330	cse->uio.uio_resid = 0;
331	cse->uio.uio_segflg = UIO_SYSSPACE;
332	cse->uio.uio_rw = UIO_WRITE;
333	cse->uio.uio_td = td;
334	cse->uio.uio_iov = cse->iovec;
335	bzero(&cse->iovec, sizeof(cse->iovec));
336	cse->uio.uio_iov[0].iov_len = cop->len;
337	cse->uio.uio_iov[0].iov_base = malloc(cop->len, M_XDATA, M_WAITOK);
338	for (i = 0; i < cse->uio.uio_iovcnt; i++)
339		cse->uio.uio_resid += cse->uio.uio_iov[0].iov_len;
340
341	crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL));
342	if (crp == NULL) {
343		error = ENOMEM;
344		goto bail;
345	}
346
347	if (cse->thash) {
348		crda = crp->crp_desc;
349		if (cse->txform)
350			crde = crda->crd_next;
351	} else {
352		if (cse->txform)
353			crde = crp->crp_desc;
354		else {
355			error = EINVAL;
356			goto bail;
357		}
358	}
359
360	if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len)))
361		goto bail;
362
363	if (crda) {
364		crda->crd_skip = 0;
365		crda->crd_len = cop->len;
366		crda->crd_inject = 0;	/* ??? */
367
368		crda->crd_alg = cse->mac;
369		crda->crd_key = cse->mackey;
370		crda->crd_klen = cse->mackeylen * 8;
371	}
372
373	if (crde) {
374		if (cop->op == COP_ENCRYPT)
375			crde->crd_flags |= CRD_F_ENCRYPT;
376		else
377			crde->crd_flags &= ~CRD_F_ENCRYPT;
378		crde->crd_len = cop->len;
379		crde->crd_inject = 0;
380
381		crde->crd_alg = cse->cipher;
382		crde->crd_key = cse->key;
383		crde->crd_klen = cse->keylen * 8;
384	}
385
386	crp->crp_ilen = cop->len;
387	crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
388		       | (cop->flags & COP_F_BATCH);
389	crp->crp_buf = (caddr_t)&cse->uio;
390	crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
391	crp->crp_sid = cse->sid;
392	crp->crp_opaque = (void *)cse;
393
394	if (cop->iv) {
395		if (crde == NULL) {
396			error = EINVAL;
397			goto bail;
398		}
399		if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
400			error = EINVAL;
401			goto bail;
402		}
403		if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize)))
404			goto bail;
405		bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize);
406		crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
407		crde->crd_skip = 0;
408	} else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
409		crde->crd_skip = 0;
410	} else if (crde) {
411		crde->crd_flags |= CRD_F_IV_PRESENT;
412		crde->crd_skip = cse->txform->blocksize;
413		crde->crd_len -= cse->txform->blocksize;
414	}
415
416	if (cop->mac) {
417		if (crda == NULL) {
418			error = EINVAL;
419			goto bail;
420		}
421		crp->crp_mac=cse->tmp_mac;
422	}
423
424	/*
425	 * Let the dispatch run unlocked, then, interlock against the
426	 * callback before checking if the operation completed and going
427	 * to sleep.  This insures drivers don't inherit our lock which
428	 * results in a lock order reversal between crypto_dispatch forced
429	 * entry and the crypto_done callback into us.
430	 */
431	error = crypto_dispatch(crp);
432	mtx_lock(&cse->lock);
433	if (error == 0 && (crp->crp_flags & CRYPTO_F_DONE) == 0)
434		error = msleep(crp, &cse->lock, PWAIT, "crydev", 0);
435	mtx_unlock(&cse->lock);
436
437	if (error != 0)
438		goto bail;
439
440	if (crp->crp_etype != 0) {
441		error = crp->crp_etype;
442		goto bail;
443	}
444
445	if (cse->error) {
446		error = cse->error;
447		goto bail;
448	}
449
450	if (cop->dst &&
451	    (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len)))
452		goto bail;
453
454	if (cop->mac &&
455	    (error = copyout(crp->crp_mac, cop->mac, cse->thash->authsize)))
456		goto bail;
457
458bail:
459	if (crp)
460		crypto_freereq(crp);
461	if (cse->uio.uio_iov[0].iov_base)
462		free(cse->uio.uio_iov[0].iov_base, M_XDATA);
463
464	return (error);
465}
466
467static int
468cryptodev_cb(void *op)
469{
470	struct cryptop *crp = (struct cryptop *) op;
471	struct csession *cse = (struct csession *)crp->crp_opaque;
472
473	cse->error = crp->crp_etype;
474	if (crp->crp_etype == EAGAIN)
475		return crypto_dispatch(crp);
476	mtx_lock(&cse->lock);
477	wakeup_one(crp);
478	mtx_unlock(&cse->lock);
479	return (0);
480}
481
482static int
483cryptodevkey_cb(void *op)
484{
485	struct cryptkop *krp = (struct cryptkop *) op;
486
487	wakeup(krp);
488	return (0);
489}
490
491static int
492cryptodev_key(struct crypt_kop *kop)
493{
494	struct cryptkop *krp = NULL;
495	int error = EINVAL;
496	int in, out, size, i;
497
498	if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
499		return (EFBIG);
500	}
501
502	in = kop->crk_iparams;
503	out = kop->crk_oparams;
504	switch (kop->crk_op) {
505	case CRK_MOD_EXP:
506		if (in == 3 && out == 1)
507			break;
508		return (EINVAL);
509	case CRK_MOD_EXP_CRT:
510		if (in == 6 && out == 1)
511			break;
512		return (EINVAL);
513	case CRK_DSA_SIGN:
514		if (in == 5 && out == 2)
515			break;
516		return (EINVAL);
517	case CRK_DSA_VERIFY:
518		if (in == 7 && out == 0)
519			break;
520		return (EINVAL);
521	case CRK_DH_COMPUTE_KEY:
522		if (in == 3 && out == 1)
523			break;
524		return (EINVAL);
525	default:
526		return (EINVAL);
527	}
528
529	krp = (struct cryptkop *)malloc(sizeof *krp, M_XDATA, M_WAITOK);
530	if (!krp)
531		return (ENOMEM);
532	bzero(krp, sizeof *krp);
533	krp->krp_op = kop->crk_op;
534	krp->krp_status = kop->crk_status;
535	krp->krp_iparams = kop->crk_iparams;
536	krp->krp_oparams = kop->crk_oparams;
537	krp->krp_status = 0;
538	krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
539
540	for (i = 0; i < CRK_MAXPARAM; i++)
541		krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
542	for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
543		size = (krp->krp_param[i].crp_nbits + 7) / 8;
544		if (size == 0)
545			continue;
546		MALLOC(krp->krp_param[i].crp_p, caddr_t, size, M_XDATA, M_WAITOK);
547		if (i >= krp->krp_iparams)
548			continue;
549		error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size);
550		if (error)
551			goto fail;
552	}
553
554	error = crypto_kdispatch(krp);
555	if (error)
556		goto fail;
557	error = tsleep(krp, PSOCK, "crydev", 0);
558	if (error) {
559		/* XXX can this happen?  if so, how do we recover? */
560		goto fail;
561	}
562
563	if (krp->krp_status != 0) {
564		error = krp->krp_status;
565		goto fail;
566	}
567
568	for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
569		size = (krp->krp_param[i].crp_nbits + 7) / 8;
570		if (size == 0)
571			continue;
572		error = copyout(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size);
573		if (error)
574			goto fail;
575	}
576
577fail:
578	if (krp) {
579		kop->crk_status = krp->krp_status;
580		for (i = 0; i < CRK_MAXPARAM; i++) {
581			if (krp->krp_param[i].crp_p)
582				FREE(krp->krp_param[i].crp_p, M_XDATA);
583		}
584		free(krp, M_XDATA);
585	}
586	return (error);
587}
588
589/* ARGSUSED */
590static int
591cryptof_poll(
592	struct file *fp,
593	int events,
594	struct ucred *active_cred,
595	struct thread *td)
596{
597
598	return (0);
599}
600
601/* ARGSUSED */
602static int
603cryptof_kqfilter(struct file *fp, struct knote *kn)
604{
605
606	return (0);
607}
608
609/* ARGSUSED */
610static int
611cryptof_stat(
612	struct file *fp,
613	struct stat *sb,
614	struct ucred *active_cred,
615	struct thread *td)
616{
617
618	return (EOPNOTSUPP);
619}
620
621/* ARGSUSED */
622static int
623cryptof_close(struct file *fp, struct thread *td)
624{
625	struct fcrypt *fcr = fp->f_data;
626	struct csession *cse;
627
628	while ((cse = TAILQ_FIRST(&fcr->csessions))) {
629		TAILQ_REMOVE(&fcr->csessions, cse, next);
630		(void)csefree(cse);
631	}
632	FREE(fcr, M_XDATA);
633	fp->f_data = NULL;
634	return 0;
635}
636
637static struct csession *
638csefind(struct fcrypt *fcr, u_int ses)
639{
640	struct csession *cse;
641
642	TAILQ_FOREACH(cse, &fcr->csessions, next)
643		if (cse->ses == ses)
644			return (cse);
645	return (NULL);
646}
647
648static int
649csedelete(struct fcrypt *fcr, struct csession *cse_del)
650{
651	struct csession *cse;
652
653	TAILQ_FOREACH(cse, &fcr->csessions, next) {
654		if (cse == cse_del) {
655			TAILQ_REMOVE(&fcr->csessions, cse, next);
656			return (1);
657		}
658	}
659	return (0);
660}
661
662static struct csession *
663cseadd(struct fcrypt *fcr, struct csession *cse)
664{
665	TAILQ_INSERT_TAIL(&fcr->csessions, cse, next);
666	cse->ses = fcr->sesn++;
667	return (cse);
668}
669
670struct csession *
671csecreate(struct fcrypt *fcr, u_int64_t sid, caddr_t key, u_int64_t keylen,
672    caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac,
673    struct enc_xform *txform, struct auth_hash *thash)
674{
675	struct csession *cse;
676
677#ifdef INVARIANTS
678	/* NB: required when mtx_init is built with INVARIANTS */
679	MALLOC(cse, struct csession *, sizeof(struct csession),
680	    M_XDATA, M_NOWAIT | M_ZERO);
681#else
682	MALLOC(cse, struct csession *, sizeof(struct csession),
683	    M_XDATA, M_NOWAIT);
684#endif
685	if (cse == NULL)
686		return NULL;
687	mtx_init(&cse->lock, "cryptodev", "crypto session lock", MTX_DEF);
688	cse->key = key;
689	cse->keylen = keylen/8;
690	cse->mackey = mackey;
691	cse->mackeylen = mackeylen/8;
692	cse->sid = sid;
693	cse->cipher = cipher;
694	cse->mac = mac;
695	cse->txform = txform;
696	cse->thash = thash;
697	cseadd(fcr, cse);
698	return (cse);
699}
700
701static int
702csefree(struct csession *cse)
703{
704	int error;
705
706	error = crypto_freesession(cse->sid);
707	mtx_destroy(&cse->lock);
708	if (cse->key)
709		FREE(cse->key, M_XDATA);
710	if (cse->mackey)
711		FREE(cse->mackey, M_XDATA);
712	FREE(cse, M_XDATA);
713	return (error);
714}
715
716static int
717cryptoopen(dev_t dev, int oflags, int devtype, struct thread *td)
718{
719	return (0);
720}
721
722static int
723cryptoread(dev_t dev, struct uio *uio, int ioflag)
724{
725	return (EIO);
726}
727
728static int
729cryptowrite(dev_t dev, struct uio *uio, int ioflag)
730{
731	return (EIO);
732}
733
734static int
735cryptoioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
736{
737	struct file *f;
738	struct fcrypt *fcr;
739	int fd, error;
740
741	switch (cmd) {
742	case CRIOGET:
743		MALLOC(fcr, struct fcrypt *,
744		    sizeof(struct fcrypt), M_XDATA, M_WAITOK);
745		TAILQ_INIT(&fcr->csessions);
746		fcr->sesn = 0;
747
748		error = falloc(td, &f, &fd);
749
750		if (error) {
751			FREE(fcr, M_XDATA);
752			return (error);
753		}
754		/* falloc automatically provides an extra reference to 'f'. */
755		f->f_flag = FREAD | FWRITE;
756		f->f_type = DTYPE_CRYPTO;
757		f->f_ops = &cryptofops;
758		f->f_data = fcr;
759		*(u_int32_t *)data = fd;
760		fdrop(f, td);
761		break;
762	default:
763		error = EINVAL;
764		break;
765	}
766	return (error);
767}
768
769#define	CRYPTO_MAJOR	70		/* from openbsd */
770static struct cdevsw crypto_cdevsw = {
771	.d_open =	cryptoopen,
772	.d_read =	cryptoread,
773	.d_write =	cryptowrite,
774	.d_ioctl =	cryptoioctl,
775	.d_name =	"crypto",
776	.d_maj =	CRYPTO_MAJOR,
777};
778static dev_t crypto_dev;
779
780/*
781 * Initialization code, both for static and dynamic loading.
782 */
783static int
784cryptodev_modevent(module_t mod, int type, void *unused)
785{
786	switch (type) {
787	case MOD_LOAD:
788		if (bootverbose)
789			printf("crypto: <crypto device>\n");
790		crypto_dev = make_dev(&crypto_cdevsw, 0,
791				      UID_ROOT, GID_WHEEL, 0666,
792				      "crypto");
793		return 0;
794	case MOD_UNLOAD:
795		/*XXX disallow if active sessions */
796		destroy_dev(crypto_dev);
797		return 0;
798	}
799	return EINVAL;
800}
801
802static moduledata_t cryptodev_mod = {
803	"cryptodev",
804	cryptodev_modevent,
805	0
806};
807MODULE_VERSION(cryptodev, 1);
808DECLARE_MODULE(cryptodev, cryptodev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
809MODULE_DEPEND(cryptodev, crypto, 1, 1, 1);
810