patch: multiple-request, async-request support for /dev/crypto

Thor Lancelot Simon <[email protected]>
Newsgroups gmane.os.netbsd.devel.userlevel,gmane.os.netbsd.devel.crypto,gmane.os.netbsd.devel.kernel
Message-ID <[email protected]>
The attached patch adds ioctls for multiple request submission and
retrieval in a single system call, and for asynchronous operation via
select()/poll() to /dev/crypto.  It was written for a slightly older
NetBSD-current and I've hastily adapted it to Andrew's recent file
descriptor allocation changes, which I hope I got right -- it's well
tested before that adaptation but untested with it (caveat emptor).

With this patch and a slightly clever multithreaded application that
batches requests when pushing them to /dev/crypto we can do 84,000
trivial asymmetric operations/sec (32 bit modular math ops) to a
rather old crypto accellerator card, with a Core 2 Duo as the host.
I think it's worth the added complexity.  Even simpler applications
can benefit -- a lot -- from async operation and retrieving multiple
requests at once when poll() fires.

There is some duplicated code here in the multiple-request ioctls that
could be shared with the single-request ioctls.  It'd be a moderate pain
to clean up and I'd prefer to do that after commit so I can get this
in the tree while I have time to focus on it.  Also, there is a large
comment here describing the new ioctls and parameters which text I'll
reproduce in or move to the manual page.

I will revise the openssl engine to work as efficiently as possible with
the new ioctls added here once I sort out some issues about updating
OpenSSL itself in our tree and feeding changes back to the OpenSSL project
in an effective way.

Comments?

-- 
Thor Lancelot Simon
Coyote Point Systems, Inc.			<[email protected]>
Millerton, NY, USA
oc-multi.diff (text/plain, 57.3 KB)
diff -r -u -p opencrypto.o/crypto.c opencrypto/crypto.c
--- opencrypto.o/crypto.c	2008-02-05 07:26:13.000000000 -0500
+++ opencrypto/crypto.c	2008-03-27 01:32:44.000000000 -0400
@@ -2,6 +2,42 @@
 /*	$FreeBSD: src/sys/opencrypto/crypto.c,v 1.4.2.5 2003/02/26 00:14:05 sam Exp $	*/
 /*	$OpenBSD: crypto.c,v 1.41 2002/07/17 23:52:38 art Exp $	*/
 
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Coyote Point Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /*
  * The author of this code is Angelos D. Keromytis ([email protected])
  *
@@ -984,6 +1020,9 @@ crypto_done(struct cryptop *crp)
 	if (crypto_timing)
 		crypto_tstat(&cryptostats.cs_done, &crp->crp_tstamp);
 #endif
+
+	crp->crp_flags |= CRYPTO_F_DONE;
+
 	/*
 	 * Normal case; queue the callback for the thread.
 	 *
@@ -992,17 +1031,39 @@ crypto_done(struct cryptop *crp)
 	 * back to mark operations completed.  Thus we need
 	 * to mask both while manipulating the return queue.
 	 */
-	mutex_spin_enter(&crypto_mtx);
-	wasempty = TAILQ_EMPTY(&crp_ret_q);
-	DPRINTF(("crypto_done: queueing %08x\n", (uint32_t)crp));
-	crp->crp_flags |= CRYPTO_F_ONRETQ|CRYPTO_F_DONE;
-	TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
-	if (wasempty) {
-		DPRINTF(("crypto_done: waking cryptoret, %08x " \
-			"hit empty queue\n.", (uint32_t)crp));
-		cv_signal(&cryptoret_cv);
+  	if (crp->crp_flags & CRYPTO_F_CBIMM) {
+		/*
+	 	* Do the callback directly.  This is ok when the
+  	 	* callback routine does very little (e.g. the
+	 	* /dev/crypto callback method just does a wakeup).
+	 	*/
+#ifdef CRYPTO_TIMING
+		if (crypto_timing) {
+			/*
+		 	* NB: We must copy the timestamp before
+		 	* doing the callback as the cryptop is
+		 	* likely to be reclaimed.
+		 	*/
+			struct timespec t = crp->crp_tstamp;
+			crypto_tstat(&cryptostats.cs_cb, &t);
+			crp->crp_callback(crp);
+			crypto_tstat(&cryptostats.cs_finis, &t);
+		} else
+#endif
+		crp->crp_callback(crp);
+	} else {
+		mutex_spin_enter(&crypto_mtx);
+		wasempty = TAILQ_EMPTY(&crp_ret_q);
+		DPRINTF(("crypto_done: queueing %08x\n", (uint32_t)crp));
+		crp->crp_flags |= CRYPTO_F_ONRETQ;
+		TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
+		if (wasempty) {
+			DPRINTF(("crypto_done: waking cryptoret, %08x " \
+				"hit empty queue\n.", (uint32_t)crp));
+			cv_signal(&cryptoret_cv);
+		}
+		mutex_spin_exit(&crypto_mtx);
 	}
-	mutex_spin_exit(&crypto_mtx);
 }
 
 /*
@@ -1015,19 +1076,26 @@ crypto_kdone(struct cryptkop *krp)
 
 	if (krp->krp_status != 0)
 		cryptostats.cs_kerrs++;
+		
+	krp->krp_flags |= CRYPTO_F_DONE;
+
 	/*
 	 * The return queue is manipulated by the swi thread
 	 * and, potentially, by crypto device drivers calling
 	 * back to mark operations completed.  Thus we need
 	 * to mask both while manipulating the return queue.
 	 */
-	mutex_spin_enter(&crypto_mtx);
-	wasempty = TAILQ_EMPTY(&crp_ret_kq);
-	krp->krp_flags |= CRYPTO_F_ONRETQ|CRYPTO_F_DONE;
-	TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
-	if (wasempty)
-		cv_signal(&cryptoret_cv);
-	mutex_spin_exit(&crypto_mtx);
+	if (krp->krp_flags & CRYPTO_F_CBIMM) {
+		krp->krp_callback(krp);
+	} else {
+		mutex_spin_enter(&crypto_mtx);
+		wasempty = TAILQ_EMPTY(&crp_ret_kq);
+		krp->krp_flags |= CRYPTO_F_ONRETQ;
+		TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
+		if (wasempty)
+			cv_signal(&cryptoret_cv);
+		mutex_spin_exit(&crypto_mtx);
+	}
 }
 
 int
diff -r -u -p opencrypto.o/cryptodev.c opencrypto/cryptodev.c
--- opencrypto.o/cryptodev.c	2008-03-21 17:55:01.000000000 -0400
+++ opencrypto/cryptodev.c	2008-03-27 01:53:34.000000000 -0400
@@ -2,6 +2,42 @@
 /*	$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.4.2.4 2003/06/03 00:09:02 sam Exp $	*/
 /*	$OpenBSD: cryptodev.c,v 1.53 2002/07/10 22:21:30 mickey Exp $	*/
 
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Coyote Point Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /*
  * Copyright (c) 2001 Theo de Raadt
  *
@@ -39,6 +75,7 @@ __KERNEL_RCSID(0, "$NetBSD: cryptodev.c,
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/kmem.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/pool.h>
@@ -51,6 +88,8 @@ __KERNEL_RCSID(0, "$NetBSD: cryptodev.c,
 #include <sys/conf.h>
 #include <sys/device.h>
 #include <sys/kauth.h>
+#include <sys/select.h>
+#include <sys/poll.h>
 
 #include "opt_ocf.h"
 #include <opencrypto/cryptodev.h>
@@ -81,7 +120,11 @@ struct csession {
 
 struct fcrypt {
 	TAILQ_HEAD(csessionlist, csession) csessions;
+	TAILQ_HEAD(crprethead, cryptop) crp_ret_mq;
+	TAILQ_HEAD(krprethead, cryptkop) crp_ret_mkq;
 	int		sesn;
+	struct selinfo	sinfo;
+	u_int32_t	requestid;
 };
 
 /* For our fixed-size allocations */
@@ -97,15 +140,16 @@ static int	cryptoselect(dev_t dev, int r
 /* Declaration of cloned-device (per-ctxt) entrypoints */
 static int	cryptof_read(file_t *, off_t *, struct uio *, kauth_cred_t, int);
 static int	cryptof_write(file_t *, off_t *, struct uio *, kauth_cred_t, int);
-static int	cryptof_ioctl(file_t *, u_long, void *);
-static int	cryptof_close(file_t *);
+static int	cryptof_ioctl(file_t *, u_long, void*, struct lwp *l);
+static int	cryptof_close(file_t *, struct lwp *);
+static int 	cryptof_poll(file_t *, int , struct lwp *);
 
 static const struct fileops cryptofops = {
     cryptof_read,
     cryptof_write,
     cryptof_ioctl,
     fnullop_fcntl,
-    fnullop_poll,
+    cryptof_poll,
     fbadop_stat,
     cryptof_close,
     fnullop_kqfilter
@@ -120,12 +164,20 @@ static struct	csession *csecreate(struct
 static int	csefree(struct csession *);
 
 static int	cryptodev_op(struct csession *, struct crypt_op *, struct lwp *);
+static int	cryptodev_mop(struct fcrypt *, struct crypt_n_op *, int, struct lwp *);	
 static int	cryptodev_key(struct crypt_kop *);
+static int	cryptodev_mkey(struct fcrypt *, struct crypt_n_kop *, int);
 int	cryptodev_dokey(struct crypt_kop *kop, struct crparam kvp[]);
+static int	crypto_sessionfin(struct fcrypt *, int, u_int32_t *);
 
 static int	cryptodev_cb(void *);
 static int	cryptodevkey_cb(void *);
 
+static int	cryptodev_mcb(void *);
+static int	cryptodevkey_mcb(void *);
+
+static int 	crypto_getmstatus(struct fcrypt *, struct crypt_result_t *, int);
+static int	crypto_getstatus(struct fcrypt *, struct crypt_result_t *);
 /*
  * sysctl-able control variables for /dev/crypto now defined in crypto.c:
  * crypto_usercrypto, crypto_userasmcrypto, crypto_devallowsoft.
@@ -155,36 +207,56 @@ cryptof_ioctl(file_t *fp, u_long cmd, vo
 	struct fcrypt *fcr = fp->f_data;
 	struct csession *cse;
 	struct session_op *sop;
+	struct session_n_op snop, *psnop;
 	struct crypt_op *cop;
+	struct crypto_mop *mop;
+	struct crypto_mkop *mkop;
+	struct crypt_n_op *cnop;
+	struct crypt_n_kop *knop;
+	struct crypt_fnop *fnop;
+	struct cryptret_t *cryptret;
+	struct crypt_result_t *crypt_result;
 	struct enc_xform *txform = NULL;
 	struct auth_hash *thash = NULL;
 	u_int64_t sid;
 	u_int32_t ses;
+	u_int32_t *sesid;
 	int error = 0;
+	int first = 1;
+	size_t count;
 
 	/* backwards compatibility */
         file_t *criofp;
 	struct fcrypt *criofcr;
 	int criofd;
 
-        switch (cmd) {
+	switch (cmd) {
         case CRIOGET:   /* XXX deprecated, remove after 5.0 */
-                if ((error = fd_allocfile(&criofp, &criofd)) != 0)
-                        return error;
-                criofcr = pool_get(&fcrpl, PR_WAITOK);
+		if ((error = fd_allocfile(&criofp, &criofd)) != 0)
+			return error;
+		criofcr = pool_get(&fcrpl, PR_WAITOK);
+		if (criofcr == NULL) {
+			fd_abort(curproc, criofp, &criofd);
+			return ENOMEM;
+		}
 		mutex_spin_enter(&crypto_mtx);
-                TAILQ_INIT(&criofcr->csessions);
+		TAILQ_INIT(&criofcr->csessions);
+		TAILQ_INIT(&criofcr->crp_ret_mq);
+		TAILQ_INIT(&criofcr->crp_ret_mkq);
+		selinit(&criofcr->sinfo);
+
                 /*
                  * Don't ever return session 0, to allow detection of
                  * failed creation attempts with multi-create ioctl.
                  */
-                criofcr->sesn = 1;
+		criofcr->sesn = 1;
+		criofcr->requestid = 1;
 		mutex_spin_exit(&crypto_mtx);
-                (void)fd_clone(criofp, criofd, (FREAD|FWRITE),
+		(void)fd_clone(criofp, criofd, (FREAD|FWRITE),
 			      &cryptofops, criofcr);
-                *(u_int32_t *)data = criofd;
+		*(u_int32_t *)data = criofd;
 		return error;
-                break;
+		break;
 	case CIOCGSESSION:
 		sop = (struct session_op *)data;
 		switch (sop->cipher) {
@@ -248,6 +320,9 @@ cryptof_ioctl(file_t *fp, u_long cmd, vo
 			}
 			break;
 		case CRYPTO_RIPEMD160_HMAC:
+			thash = &auth_hash_hmac_ripemd_160;
+			break;
+		case CRYPTO_RIPEMD160_HMAC_96:
 			thash = &auth_hash_hmac_ripemd_160_96;
 			break;
 		case CRYPTO_MD5:
@@ -328,12 +403,193 @@ cryptof_ioctl(file_t *fp, u_long cmd, vo
 		mutex_spin_exit(&crypto_mtx);
 bail:
 		if (error) {
-			if (crie.cri_key)
-				FREE(crie.cri_key, M_XDATA);
-			if (cria.cri_key)
-				FREE(cria.cri_key, M_XDATA);
+			if (crie.cri_key) {
+				memset(crie.cri_key, 0, crie.cri_klen / 8);
+				free(crie.cri_key, M_XDATA);
+			}
+			if (cria.cri_key) {
+				memset(cria.cri_key, 0, cria.cri_klen / 8);
+				free(cria.cri_key, M_XDATA);
+			}
 		}
 		break;
+	case CIOCNSESSION:
+		psnop = (struct session_n_op *)data;
+		bcopy(data, (void *)&snop, sizeof(struct session_n_op));
+		do {
+			switch (snop.cipher) {
+			case 0:
+				 break;
+			case CRYPTO_DES_CBC:
+				txform = &enc_xform_des;
+				break;
+			case CRYPTO_3DES_CBC:
+				txform = &enc_xform_3des;
+				break;
+			case CRYPTO_BLF_CBC:
+				txform = &enc_xform_blf;
+				break;
+			case CRYPTO_CAST_CBC:
+				txform = &enc_xform_cast5;
+				break;
+			case CRYPTO_SKIPJACK_CBC:
+				txform = &enc_xform_skipjack;
+				break;
+			case CRYPTO_AES_CBC:
+				txform = &enc_xform_rijndael128;
+				break;
+			case CRYPTO_NULL_CBC:
+				txform = &enc_xform_null;
+				break;
+			case CRYPTO_ARC4:
+				txform = &enc_xform_arc4;
+				break;
+			default:
+				DPRINTF(("Invalid cipher %d\n", snop.cipher));
+				snop.status = EINVAL;
+				goto mbail;
+			}
+
+			switch (snop.mac) {
+			case 0:
+				break;
+			case CRYPTO_MD5_HMAC:
+				thash = &auth_hash_hmac_md5;
+				break;
+			case CRYPTO_SHA1_HMAC:
+				thash = &auth_hash_hmac_sha1;
+				break;
+			case CRYPTO_MD5_HMAC_96:
+				thash = &auth_hash_hmac_md5_96;
+				break;
+			case CRYPTO_SHA1_HMAC_96:
+				thash = &auth_hash_hmac_sha1_96;
+				break;
+			case CRYPTO_SHA2_HMAC:
+				if (snop.mackeylen == auth_hash_hmac_sha2_256.keysize)
+					thash = &auth_hash_hmac_sha2_256;
+				else if (snop.mackeylen == auth_hash_hmac_sha2_384.keysize)
+					thash = &auth_hash_hmac_sha2_384;
+				else if (snop.mackeylen == auth_hash_hmac_sha2_512.keysize)
+					thash = &auth_hash_hmac_sha2_512;
+				else {
+					DPRINTF(("Invalid mackeylen %d\n",
+					    snop.mackeylen));
+					snop.status = EINVAL;
+				}
+				break;
+			case CRYPTO_RIPEMD160_HMAC:
+				thash = &auth_hash_hmac_ripemd_160;
+				break;
+			case CRYPTO_RIPEMD160_HMAC_96:
+				thash = &auth_hash_hmac_ripemd_160_96;
+				break;
+			case CRYPTO_MD5:
+				thash = &auth_hash_md5;
+				break;
+			case CRYPTO_SHA1:
+				thash = &auth_hash_sha1;
+				break;
+			case CRYPTO_NULL_HMAC:
+				thash = &auth_hash_null;
+				break;
+			default:	
+				DPRINTF(("Invalid mac %d\n", snop.mac));
+				snop.status = EINVAL;
+				goto mbail;	
+			}
+
+			bzero(&crie, sizeof(crie));
+			bzero(&cria, sizeof(cria));
+
+			if (txform) {
+				crie.cri_alg = txform->type;
+				crie.cri_klen = snop.keylen * 8;
+				if (snop.keylen > txform->maxkey ||
+				    snop.keylen < txform->minkey) {
+					DPRINTF(("keylen %d not in [%d,%d]\n",
+					    snop.keylen, txform->minkey,
+					    txform->maxkey));
+					snop.status = EINVAL;
+					goto mbail;
+				}
+
+				crie.cri_key = malloc(crie.cri_klen / 8, 
+						    M_XDATA, M_WAITOK);
+				if((snop.status = copyin(snop.key, 
+					crie.cri_key, crie.cri_klen / 8)))
+					goto mbail;
+				if (thash)
+					crie.cri_next = &cria;
+			}
+
+			if (thash) {
+				cria.cri_alg = thash->type;
+				cria.cri_klen = snop.mackeylen * 8;
+				if (snop.mackeylen != thash->keysize) {
+					DPRINTF(("mackeylen %d != keysize %d\n",
+					    snop.mackeylen, thash->keysize));
+					snop.status = EINVAL;
+					goto mbail;
+				}
+
+				if (cria.cri_klen) {
+					cria.cri_key = malloc(cria.cri_klen / 8,
+							    M_XDATA, M_WAITOK);
+				if((snop.status = copyin(snop.mackey, 
+					cria.cri_key, cria.cri_klen / 8)))
+					goto mbail;
+				}
+			}
+			mutex_spin_enter(&crypto_mtx);
+			snop.status = crypto_newsession(&sid, 
+					    (txform ? &crie : &cria), 
+					    crypto_devallowsoft);
+			if (!snop.status) {
+				cse = csecreate(fcr, sid, crie.cri_key, 
+						crie.cri_klen, cria.cri_key, 
+						cria.cri_klen, snop.cipher, 
+						snop.mac, txform, thash);
+				if (cse != NULL) {
+					snop.ses = cse->ses;
+				} else {
+					DPRINTF(("csecreate failed\n"));
+					crypto_freesession(sid);
+					snop.status = EINVAL;
+				}
+			} else {
+				DPRINTF(("SIOCSESSION violates kernel parameters %d\n",
+								snop.status));
+			}
+			mutex_spin_exit(&crypto_mtx);
+mbail:
+			if(snop.status) {
+				snop.ses = 0;
+				if (crie.cri_key)
+					memset(crie.cri_key, 0, crie.cri_klen / 8);
+					free(crie.cri_key, M_XDATA);
+				if (cria.cri_key)
+					memset(cria.cri_key, 0, cria.cri_klen / 8);
+					free(cria.cri_key, M_XDATA);
+			}
+		
+			if(first) {
+				bcopy(&snop, psnop,
+				      sizeof(struct session_n_op));
+				first = 0;
+			} else {
+				error = copyout(&snop, psnop, 
+					    sizeof(struct session_n_op));
+			}
+
+			psnop = snop.next;
+
+			if (psnop) {
+				copyin(psnop, &snop,
+				       sizeof(struct session_n_op));
+			}
+		} while (psnop && !error);
+		break;	
 	case CIOCFSESSION:
 		mutex_spin_enter(&crypto_mtx);
 		ses = *(u_int32_t *)data;
@@ -344,6 +600,19 @@ bail:
 		error = csefree(cse);
 		mutex_spin_exit(&crypto_mtx);
 		break;
+	case CIOCFNSESSION:
+		fnop = (struct crypt_fnop *)data;
+		sesid = kmem_alloc((fnop->count * sizeof(u_int32_t)), 
+				   KM_SLEEP);
+		if (!sesid)
+			return (EINVAL);
+		error = copyin(fnop->sesid, sesid, 
+			    (fnop->count * sizeof(u_int32_t)));
+		if (!error) {
+			error = crypto_sessionfin(fcr, fnop->count, sesid);
+		}
+		kmem_free(sesid, (fnop->count * sizeof(u_int32_t)));
+		break;
 	case CIOCCRYPT:
 		mutex_spin_enter(&crypto_mtx);
 		cop = (struct crypt_op *)data;
@@ -356,13 +625,80 @@ bail:
 		error = cryptodev_op(cse, cop, curlwp);
 		DPRINTF(("cryptodev_op error = %d\n", error));
 		break;
+	case CIOCNCRYPTM:
+		mop = (struct crypto_mop *)data;
+		cnop = kmem_alloc((mop->count * sizeof(struct crypt_n_op)),
+				  KM_SLEEP);
+		if(!cnop) {
+			return(EINVAL);
+		}
+		error = copyin(mop->reqs, cnop, 
+			    (mop->count * sizeof(struct crypt_n_op)));
+		if(!error) {
+			error = cryptodev_mop(fcr, cnop, mop->count, l);
+			if (!error) {
+				error = copyout(cnop, mop->reqs, 
+					        (mop->count *
+						 sizeof(struct crypt_n_op)));
+			}
+		}
+		kmem_free(cnop, (mop->count * sizeof(struct crypt_n_op)));
+		break;		
 	case CIOCKEY:
 		error = cryptodev_key((struct crypt_kop *)data);
 		DPRINTF(("cryptodev_key error = %d\n", error));
 		break;
+	case CIOCNFKEYM:
+		mkop = (struct crypto_mkop *)data;
+		knop = kmem_alloc((mkop->count * sizeof(struct crypt_n_kop)),
+				  KM_SLEEP);
+		if (!knop) {
+			return(EINVAL);
+		}
+		error = copyin(mkop->reqs, knop,
+			    (mkop->count * sizeof(struct crypt_n_kop)));
+		if (!error) {
+			error = cryptodev_mkey(fcr, knop, mkop->count);
+			if (!error)
+				error = copyout(knop, mkop->reqs,
+			    			(mkop->count *
+						 sizeof(struct crypt_n_kop)));
+		}
+		kmem_free(knop, (mkop->count * sizeof(struct crypt_n_kop)));
+		break;
 	case CIOCASYMFEAT:
 		error = crypto_getfeat((int *)data);
 		break;
+	case CIOCNCRYPTRETM:
+		cryptret = (struct cryptret_t *)data;
+		count = cryptret->count;
+		crypt_result = kmem_alloc((count * 
+				      sizeof(struct crypt_result_t)),  
+				      KM_SLEEP);
+		if(!crypt_result)
+			return(EINVAL);
+		error = copyin(cryptret->results, crypt_result,
+			    (count * sizeof(struct crypt_result_t)));
+		if (error)
+			goto reterr;
+		cryptret->count = crypto_getmstatus(fcr, crypt_result,
+					cryptret->count);
+		/* sanity check count */
+		if (cryptret->count > count) {
+			printf("%s.%d: error returned count %d > original count %d\n",
+					__FILE__, __LINE__, cryptret->count, count);
+			cryptret->count = count;
+
+		}
+		error = copyout(crypt_result, cryptret->results,
+			    (cryptret->count * sizeof(struct crypt_result_t)));
+reterr:
+		kmem_free(crypt_result,
+			  (count * sizeof(struct crypt_result_t)));
+		break;
+	case CIOCNCRYPTRET:
+		error = crypto_getstatus(fcr, (struct crypt_result_t *)data); 
+		break;
 	default:
 		DPRINTF(("invalid ioctl cmd %ld\n", cmd));
 		error = EINVAL;
@@ -393,7 +729,7 @@ cryptodev_op(struct csession *cse, struc
 	UIO_SETUP_SYSSPACE(&cse->uio);
 	memset(&cse->iovec, 0, sizeof(cse->iovec));
 	cse->uio.uio_iov[0].iov_len = cop->len;
-	cse->uio.uio_iov[0].iov_base = malloc(cop->len, M_XDATA, M_WAITOK);
+	cse->uio.uio_iov[0].iov_base = kmem_alloc(cop->len, KM_SLEEP);
 	cse->uio.uio_resid = cse->uio.uio_iov[0].iov_len;
 
 	crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL));
@@ -416,7 +752,10 @@ cryptodev_op(struct csession *cse, struc
 	}
 
 	if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len)))
+	{
+		printf("copyin failed %s %d \n", (char *)cop->src, error);
 		goto bail;
+	}
 
 	if (crda) {
 		crda->crd_skip = 0;
@@ -442,8 +781,7 @@ cryptodev_op(struct csession *cse, struc
 	}
 
 	crp->crp_ilen = cop->len;
-	crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
-		       | (cop->flags & COP_F_BATCH);
+	crp->crp_flags = CRYPTO_F_IOV | (cop->flags & COP_F_BATCH);
 	crp->crp_buf = (void *)&cse->uio;
 	crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
 	crp->crp_sid = cse->sid;
@@ -458,7 +796,8 @@ cryptodev_op(struct csession *cse, struc
 			error = EINVAL;
 			goto bail;
 		}
-		if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize)))
+		if ((error = copyin(cop->iv, cse->tmp_iv,
+				    cse->txform->blocksize)))
 			goto bail;
 		bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize);
 		crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
@@ -491,13 +830,27 @@ cryptodev_op(struct csession *cse, struc
 	 * XXX     (should we arrange for crypto_dispatch to return to
 	 * XXX      us with it held?  it seems quite ugly to do so.)
 	 */
+#ifdef notyet
+eagain:
+#endif
 	error = crypto_dispatch(crp);
 	mutex_spin_enter(&crypto_mtx);
-	if (error != 0) {
+
+	switch (error) {
+#ifdef notyet	/* don't loop forever -- but EAGAIN not possible here yet */
+	case EAGAIN:
+		mutex_spin_exit(&crypto_mtx);
+		goto eagain;
+		break;
+#endif
+	case 0:
+		break;
+	default:
 		DPRINTF(("cryptodev_op: not waiting, error.\n"));
 		mutex_spin_exit(&crypto_mtx);
 		goto bail;
 	}
+		
 	while (!(crp->crp_flags & CRYPTO_F_DONE)) {
 		DPRINTF(("cryptodev_op: sleeping on cv %08x for crp %08x\n", \
 			(uint32_t)&crp->crp_cv, (uint32_t)crp));
@@ -522,7 +875,8 @@ cryptodev_op(struct csession *cse, struc
 	}
 
 	if (cop->dst &&
-	    (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len))) {
+	    (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len)))
+	{
 		DPRINTF(("cryptodev_op: copyout error %d\n", error));
 		goto bail;
 	}
@@ -537,7 +891,8 @@ bail:
 	if (crp)
 		crypto_freereq(crp);
 	if (cse->uio.uio_iov[0].iov_base)
-		free(cse->uio.uio_iov[0].iov_base, M_XDATA);
+		kmem_free(cse->uio.uio_iov[0].iov_base,
+			  cse->uio.uio_iov[0].iov_len);
 
 	return (error);
 }
@@ -565,13 +920,50 @@ cryptodev_cb(void *op)
 }
 
 static int
+cryptodev_mcb(void *op)
+{
+	struct cryptop *crp = (struct cryptop *) op;
+	struct csession *cse = (struct csession *)crp->crp_opaque;
+	int  error=0;
+
+	mutex_spin_enter(&crypto_mtx);
+	cse->error = crp->crp_etype;
+	if (crp->crp_etype == EAGAIN) {
+		mutex_spin_exit(&crypto_mtx);
+		error = crypto_dispatch(crp);
+		mutex_spin_enter(&crypto_mtx);
+	}
+	if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
+		cv_signal(&crp->crp_cv);
+	}
+
+	TAILQ_INSERT_TAIL(&crp->fcrp->crp_ret_mq, crp, crp_next);
+	mutex_spin_exit(&crypto_mtx);
+	selnotify(&crp->fcrp->sinfo, 0, 0);
+	return (0);
+}
+
+static int
 cryptodevkey_cb(void *op)
 {
 	struct cryptkop *krp = (struct cryptkop *) op;
+	
+	mutex_spin_enter(&crypto_mtx);
+	cv_signal(&krp->krp_cv);
+	mutex_spin_exit(&crypto_mtx);
+	return (0);
+}
+
+static int
+cryptodevkey_mcb(void *op)
+{
+	struct cryptkop *krp = (struct cryptkop *) op;
 
 	mutex_spin_enter(&crypto_mtx);
 	cv_signal(&krp->krp_cv);
+	TAILQ_INSERT_TAIL(&krp->fcrp->crp_ret_mkq, krp, krp_next);
 	mutex_spin_exit(&crypto_mtx);
+	selnotify(&krp->fcrp->sinfo,0);
 	return (0);
 }
 
@@ -655,7 +1047,7 @@ cryptodev_key(struct crypt_kop *kop)
 		size = (krp->krp_param[i].crp_nbits + 7) / 8;
 		if (size == 0)
 			continue;
-		krp->krp_param[i].crp_p = malloc(size, M_XDATA, M_WAITOK);
+		krp->krp_param[i].crp_p = kmem_alloc(size, KM_SLEEP);
 		if (i >= krp->krp_iparams)
 			continue;
 		error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size);
@@ -699,8 +1091,13 @@ fail:
 	if (krp) {
 		kop->crk_status = krp->krp_status;
 		for (i = 0; i < CRK_MAXPARAM; i++) {
-			if (krp->krp_param[i].crp_p)
-				FREE(krp->krp_param[i].crp_p, M_XDATA);
+			struct crparam *kp = &(krp->krp_param[i]);
+			if (krp->krp_param[i].crp_p) {
+				size = (kp->crp_nbits + 7)  / 8;
+				KASSERT(size > 0);
+				memset(kp->crp_p, 0, size);
+				kmem_free(kp->crp_p, size);
+			}
 		}
 		pool_put(&cryptkop_pool, krp);
 	}
@@ -720,6 +1117,7 @@ cryptof_close(file_t *fp)
 		TAILQ_REMOVE(&fcr->csessions, cse, next);
 		(void)csefree(cse);
 	}
+	seldestroy(&fcr->sinfo);
 	pool_put(&fcrpl, fcr);
 
 	fp->f_data = NULL;
@@ -738,6 +1136,7 @@ csefind(struct fcrypt *fcr, u_int ses)
 	TAILQ_FOREACH(cse, &fcr->csessions, next)
 		if (cse->ses == ses)
 			ret = cse;
+	
 	return (ret);
 }
 
@@ -809,9 +1208,9 @@ csefree(struct csession *cse)
 	KASSERT(mutex_owned(&crypto_mtx));
 	error = crypto_freesession(cse->sid);
 	if (cse->key)
-		FREE(cse->key, M_XDATA);
+		free(cse->key, M_XDATA);
 	if (cse->mackey)
-		FREE(cse->mackey, M_XDATA);
+		free(cse->mackey, M_XDATA);
 	pool_put(&csepl, cse);
 	return (error);
 }
@@ -831,13 +1230,21 @@ cryptoopen(dev_t dev, int flag, int mode
 		return error;
 
 	fcr = pool_get(&fcrpl, PR_WAITOK);
+	if (fcr == NULL) {
+		fdrelease(l, fd);
+		return ENOMEM;
+	}
 	mutex_spin_enter(&crypto_mtx);
 	TAILQ_INIT(&fcr->csessions);
+	TAILQ_INIT(&fcr->crp_ret_mq);
+	TAILQ_INIT(&fcr->crp_ret_mkq);
+	selinit(&fcr->sinfo);
 	/*
 	 * Don't ever return session 0, to allow detection of
 	 * failed creation attempts with multi-create ioctl.
 	 */
 	fcr->sesn = 1;
+	fcr->requestid = 1;
 	mutex_spin_exit(&crypto_mtx);
 	return fd_clone(fp, fd, flag, &cryptofops, fcr);
 }
@@ -875,6 +1282,622 @@ struct cdevsw crypto_cdevsw = {
 	/* type */	D_OTHER,
 };
 
+static int 
+cryptodev_mop(struct fcrypt *fcr, 
+              struct crypt_n_op * cnop,
+              int count,
+              struct lwp *l)
+{
+	struct cryptop *crp = NULL;
+	struct cryptodesc *crde = NULL, *crda = NULL;
+	int req, error=0;
+	struct csession *cse;
+
+	for (req = 0; req < count; req++) {
+		mutex_spin_enter(&crypto_mtx);
+		cse = csefind(fcr, cnop[req].ses);
+		if (cse == NULL) {
+			DPRINTF(("csefind failed\n"));
+			cnop[req].status = EINVAL;
+			mutex_spin_exit(&crypto_mtx);
+			continue;
+		}
+		mutex_spin_exit(&crypto_mtx);
+	
+		if (cnop[req].len > 256*1024-4) {
+			DPRINTF(("length failed\n"));
+			cnop[req].status = EINVAL;
+			continue;
+		}
+		if (cse->txform) {
+			if (cnop[req].len == 0 || 
+			    (cnop[req].len % cse->txform->blocksize) != 0) { 
+				cnop[req].status = EINVAL;
+				continue;
+			}
+		}
+
+		crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL));
+		if (crp == NULL) {
+			cnop[req].status = ENOMEM;
+			goto bail;
+		}
+
+		bzero(&crp->uio, sizeof(crp->uio));
+		crp->uio.uio_iovcnt = 1;
+		crp->uio.uio_resid = 0;
+		crp->uio.uio_rw = UIO_WRITE;
+		crp->uio.uio_iov = crp->iovec;
+		UIO_SETUP_SYSSPACE(&crp->uio);
+		memset(&crp->iovec, 0, sizeof(crp->iovec));
+		crp->uio.uio_iov[0].iov_len = cnop[req].len;
+		crp->uio.uio_iov[0].iov_base = kmem_alloc(cnop[req].len,
+							  KM_SLEEP);
+		crp->uio.uio_resid = crp->uio.uio_iov[0].iov_len;
+
+		if (cse->thash) {
+			crda = crp->crp_desc;
+			if (cse->txform)
+				crde = crda->crd_next;
+		} else {
+			if (cse->txform)
+				crde = crp->crp_desc;
+			else {
+				cnop[req].status = EINVAL;
+				goto bail;	
+			}
+		}
+
+		if ((copyin(cnop[req].src, 
+		    crp->uio.uio_iov[0].iov_base, cnop[req].len))) {
+			cnop[req].status = EINVAL;
+			goto bail;
+		}
+	
+		if (crda) {
+			crda->crd_skip = 0;
+			crda->crd_len = cnop[req].len;
+			crda->crd_inject = 0;	/* ??? */
+
+			crda->crd_alg = cse->mac;
+			crda->crd_key = cse->mackey;
+			crda->crd_klen = cse->mackeylen * 8;
+		}
+
+		if (crde) {
+			if (cnop[req].op == COP_ENCRYPT)
+				crde->crd_flags |= CRD_F_ENCRYPT;
+			else
+				crde->crd_flags &= ~CRD_F_ENCRYPT;
+			crde->crd_len = cnop[req].len;
+			crde->crd_inject = 0;
+
+			crde->crd_alg = cse->cipher;
+			if(cnop[req].key && cnop[req].keylen) {
+				crde->crd_key = malloc(cnop[req].keylen,
+						    M_XDATA, M_WAITOK);
+				if((error = copyin(cnop[req].key, 
+				    crde->crd_key, cnop[req].keylen))) {
+					cnop[req].status = EINVAL;
+					goto bail;
+				}
+				crde->crd_klen =  cnop[req].keylen * 8;
+			} else {
+				crde->crd_key = cse->key;
+				crde->crd_klen = cse->keylen * 8;
+			}
+		}
+
+		crp->crp_ilen = cnop[req].len;
+		crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
+				    | (cnop[req].flags & COP_F_BATCH);
+		crp->crp_buf = (void *)&crp->uio;
+		crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_mcb;
+		crp->crp_sid = cse->sid;
+		crp->crp_opaque = (void *)cse;
+		crp->fcrp = fcr;
+		crp->dst = cnop[req].dst;
+		/* we can use the crp_ilen in cryptop(crp) for this */
+		crp->len = cnop[req].len;
+		crp->mac = cnop[req].mac;
+
+		if (cnop[req].iv) {
+			if (crde == NULL) {
+				cnop[req].status = EINVAL;
+				goto bail;
+			}
+			if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
+				cnop[req].status = EINVAL;
+				goto bail;
+			}
+			if ((error = copyin(cnop[req].iv, crp->tmp_iv,
+			    cse->txform->blocksize))) {
+				cnop[req].status = EINVAL;
+				goto bail;
+			}
+			bcopy(crp->tmp_iv, crde->crd_iv, cse->txform->blocksize);
+			crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
+			crde->crd_skip = 0;
+		} else if (crde) {
+			if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
+				crde->crd_skip = 0;
+			} else {
+				crde->crd_flags |= CRD_F_IV_PRESENT;
+				crde->crd_skip = cse->txform->blocksize;
+				crde->crd_len -= cse->txform->blocksize;
+			}
+		}
+	
+		if (cnop[req].mac) {
+			if (crda == NULL) {
+				cnop[req].status = EINVAL;
+				goto bail;
+			}
+			crp->crp_mac=cse->tmp_mac;
+		}
+		cnop[req].reqid = atomic_inc_32_nv(&(fcr->requestid));
+		crp->crp_reqid = cnop[req].reqid;
+		crp->crp_usropaque = cnop[req].opaque;
+#ifdef notyet
+eagain:
+#endif
+		cnop[req].status = crypto_dispatch(crp);
+		mutex_spin_enter(&crypto_mtx);	/* XXX why mutex? */
+
+		switch (cnop[req].status) {
+#ifdef notyet	/* don't loop forever -- but EAGAIN not possible here yet */
+		case EAGAIN:
+			mutex_spin_exit(&crypto_mtx);
+			goto eagain;
+			break;
+#endif
+		case 0:
+			break;
+		default:
+			DPRINTF(("cryptodev_op: not waiting, error.\n"));
+			mutex_spin_exit(&crypto_mtx);
+			goto bail;
+		}
+
+		mutex_spin_exit(&crypto_mtx);
+bail:
+		if (cnop[req].status) {
+			if (crp) {
+				crypto_freereq(crp);
+				if(cse->uio.uio_iov[0].iov_base) {
+					kmem_free(cse->uio.uio_iov[0].iov_base,
+						  cse->uio.uio_iov[0].iov_len);
+				}
+			}
+			error = 0;
+		}
+	}
+	return (error);
+}
+
+static int
+cryptodev_mkey(struct fcrypt *fcr, struct crypt_n_kop *kop, int count)
+{
+	struct cryptkop *krp = NULL;
+	int error = EINVAL;
+	int in, out, size, i, req;
+
+	for (req = 0; req < count; req++) {
+		if (kop[req].crk_iparams + kop[req].crk_oparams > CRK_MAXPARAM) {
+			return (EFBIG);
+		}
+
+		in = kop[req].crk_iparams;
+		out = kop[req].crk_oparams;
+		switch (kop[req].crk_op) {
+		case CRK_MOD_EXP:
+			if (in == 3 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD_EXP_CRT:
+			if (in == 6 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_DSA_SIGN:
+			if (in == 5 && out == 2)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_DSA_VERIFY:
+			if (in == 7 && out == 0)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_DH_COMPUTE_KEY:
+			if (in == 3 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD_ADD:
+			if (in == 3 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD_ADDINV:
+			if (in == 2 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD_SUB:
+			if (in == 3 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD_MULT:
+			if (in == 3 && out == 1)
+				break;	
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD_MULTINV:
+			if (in == 2 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		case CRK_MOD:
+			if (in == 2 && out == 1)
+				break;
+			kop[req].status = EINVAL;
+			continue;
+		default:
+			kop[req].status = EINVAL;
+			continue;
+		}
+
+		krp = pool_get(&cryptkop_pool, PR_WAITOK);
+		if (!krp) {
+			kop[req].status = ENOMEM;
+			goto fail;
+		}
+		bzero(krp, sizeof *krp);
+		cv_init(&krp->krp_cv, "crykdev");
+		krp->krp_op = kop[req].crk_op;
+		krp->krp_status = kop[req].crk_status;
+		krp->krp_iparams = kop[req].crk_iparams;
+		krp->krp_oparams = kop[req].crk_oparams;
+		krp->krp_status = 0;
+		krp->krp_callback =
+		    (int (*) (struct cryptkop *)) cryptodevkey_mcb;
+		bcopy(kop[req].crk_param,
+		      krp->crk_param,
+		      sizeof(kop[req].crk_param));
+
+		krp->krp_flags = CRYPTO_F_CBIMM;
+
+		for (i = 0; i < CRK_MAXPARAM; i++)
+			krp->krp_param[i].crp_nbits =
+			    kop[req].crk_param[i].crp_nbits;
+		for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
+			size = (krp->krp_param[i].crp_nbits + 7) / 8;
+			if (size == 0)
+				continue;
+			krp->krp_param[i].crp_p =
+			    kmem_alloc(size, KM_SLEEP);
+			if (i >= krp->krp_iparams)
+				continue;
+			kop[req].status = copyin(kop[req].crk_param[i].crp_p,
+						krp->krp_param[i].crp_p, size);
+			if (kop[req].status)
+				goto fail;
+		}
+		krp->fcrp = fcr;
+
+		kop[req].reqid = atomic_inc_32_nv(&(fcr->requestid));
+		krp->krp_reqid = kop[req].reqid;
+		krp->krp_usropaque = kop[req].crk_opaque;
+
+		kop[req].status = crypto_kdispatch(krp);
+		if (kop[req].status != 0) {
+			goto fail;
+		}
+
+fail:
+		if(kop[req].status) {
+			if (krp) {
+				kop[req].crk_status = krp->krp_status;
+				for (i = 0; i < CRK_MAXPARAM; i++) {
+					struct crparam *kp =
+						&(krp->krp_param[i]);
+					if (kp->crp_p) {
+						size = (kp->crp_nbits + 7) / 8;
+						KASSERT(size > 0);
+						memset(kp->crp_p, 0, size);
+						kmem_free(kp->crp_p, size);
+					}
+				}
+				pool_put(&cryptkop_pool, krp);
+			}
+		}
+		error = 0;
+	}
+	DPRINTF(("cryptodev_key: error=0x%08x\n", error));
+	return (error);
+}
+
+static int
+crypto_sessionfin(struct fcrypt *fcr, int count, u_int32_t *sesid)
+{
+	struct csession *cse;
+	int req, error = 0;
+
+	mutex_spin_enter(&crypto_mtx);
+	for(req = 0; req < count; req++) {
+		cse = csefind(fcr, sesid[req]);
+		if (cse == NULL)
+			continue;
+		csedelete(fcr, cse);
+		error = csefree(cse);
+	}
+	mutex_spin_exit(&crypto_mtx);
+	return 0;
+}
+
+/*
+ * collect as many completed requests as are availble, or count completed requests
+ * whichever is less.
+ * return the number of requests.
+ */
+static int
+crypto_getmstatus(struct fcrypt *fcr, struct crypt_result_t *crypt_result, int count)
+{
+	struct cryptop *crp = NULL;
+	struct cryptkop *krp = NULL;
+	struct csession *cse;
+	int i, size, req = 0;
+	int completed=0;
+
+	/* On stack so nobody else can grab them -- no locking */
+	SLIST_HEAD(, cryptop) crp_delfree_l =
+	    SLIST_HEAD_INITIALIZER(crp_delfree_l);
+	SLIST_HEAD(, cryptkop) krp_delfree_l =
+	    SLIST_HEAD_INITIALIZER(krp_delfree_l);
+
+	mutex_spin_enter(&crypto_mtx);
+
+	/* at this point we do not know which response user is requesting for 
+	 * (symmetric or asymmetric) so we copyout one from each i.e if the 
+	 * count is 2 then 1 from symmetric and 1 from asymmetric queue and 
+	 * if 3 then 2 symmetric and 1 asymmetric and so on */
+	for(; req < count ;) {
+		crp = TAILQ_FIRST(&fcr->crp_ret_mq);
+		if(crp) {
+			cse = (struct csession *)crp->crp_opaque;
+			crypt_result[req].rid = crp->crp_reqid;
+			crypt_result[req].opaque = crp->crp_usropaque;
+			completed++;
+			cse = csefind(fcr, cse->ses);
+			if (cse == NULL) {
+				DPRINTF(("csefind failed\n"));
+				crypt_result[req].status = EINVAL;
+				goto bail;
+			}
+			
+			if (crp->crp_etype != 0) {
+				crypt_result[req].status = crp->crp_etype;
+				goto bail;
+			}
+
+			if (cse->error) {
+				crypt_result[req].status = cse->error;
+				goto bail;
+			}
+
+			if (crp->dst &&
+			    (crypt_result[req].status = copyout
+						(crp->uio.uio_iov[0].iov_base,
+			    			crp->dst, crp->len)))
+				goto bail;
+
+			if (crp->mac &&
+			    (crypt_result[req].status = copyout
+						(crp->crp_mac, crp->mac,
+			    			cse->thash->authsize)))
+				goto bail;
+bail:
+			TAILQ_REMOVE(&fcr->crp_ret_mq, crp, crp_next);
+			SLIST_INSERT_HEAD(&crp_delfree_l, crp,
+					  crp_qun.crp_lnext);
+			req++;
+		}
+
+		if(req < count) {
+			krp = TAILQ_FIRST(&fcr->crp_ret_mkq);
+			if (krp) {
+				crypt_result[req].rid = krp->krp_reqid;
+				crypt_result[req].opaque = krp->krp_usropaque;
+				completed++;
+				if (krp->krp_status != 0) {
+					DPRINTF(("cryptodev_key: "
+						 "krp->krp_status"
+						"0x%08x\n", krp->krp_status));
+					crypt_result[req].status =
+					    krp->krp_status;
+					goto fail;
+				}
+
+				for (i = krp->krp_iparams; i < krp->krp_iparams
+						 + krp->krp_oparams; i++) {
+					size = (krp->krp_param[i].crp_nbits
+						+ 7) / 8;
+					if (size == 0)
+						continue;
+					crypt_result[req].status = copyout
+					    (krp->krp_param[i].crp_p,
+					    krp->crk_param[i].crp_p, size);
+					if (crypt_result[req].status) {
+						DPRINTF(("cryptodev_key: "
+							 "copyout oparam "
+						  	 "%d failed, "
+							 "error=%d\n",
+							 i-krp->krp_iparams, 
+						  crypt_result[req].status));
+						goto fail;
+					}
+				}
+fail:
+				TAILQ_REMOVE(&fcr->crp_ret_mkq, krp, krp_next);
+				/* not sure what to do for this */
+				/* kop[req].crk_status = krp->krp_status; */ 
+				SLIST_INSERT_HEAD(&krp_delfree_l, krp,
+						  krp_qun.krp_lnext);
+			}
+			req++;
+		}
+	}
+	mutex_spin_exit(&crypto_mtx);
+
+	while(!SLIST_EMPTY(&crp_delfree_l)) {
+		crp = SLIST_FIRST(&crp_delfree_l);
+		SLIST_REMOVE_HEAD(&crp_delfree_l, crp_qun.crp_lnext);
+		kmem_free(crp->uio.uio_iov[0].iov_base,
+			  crp->uio.uio_iov[0].iov_len);
+		crypto_freereq(crp);
+	}
+	
+	while(!SLIST_EMPTY(&krp_delfree_l)) {
+		krp = SLIST_FIRST(&krp_delfree_l);
+		for (i = 0; i < CRK_MAXPARAM; i++) {
+			struct crparam *kp = &(krp->krp_param[i]);
+			if (kp->crp_p) {
+			    size = (kp->crp_nbits + 7) / 8;
+			    KASSERT(size > 0);
+			    memset(kp->crp_p, 0, size);
+			    kmem_free(kp->crp_p, size);
+			}
+		}
+		SLIST_REMOVE_HEAD(&krp_delfree_l, krp_qun.krp_lnext);
+		pool_put(&cryptkop_pool, krp);
+	}
+	return completed;	
+}
+
+static int
+crypto_getstatus (struct fcrypt *fcr, struct crypt_result_t *crypt_result)
+{
+        struct cryptop *crp = NULL;
+        struct cryptkop *krp = NULL;
+        struct csession *cse;
+        int i, size, req = 0;
+
+	mutex_spin_enter(&crypto_mtx);		
+	/* Here we dont know for which request the user is requesting the 
+	 * response so checking in both the queues */
+	TAILQ_FOREACH(crp, &fcr->crp_ret_mq, crp_next) {
+		if(crp && (crp->crp_reqid == crypt_result->rid)) {
+			cse = (struct csession *)crp->crp_opaque;
+		        crypt_result->opaque = crp->crp_usropaque;
+			cse = csefind(fcr, cse->ses);
+			if (cse == NULL) {
+				DPRINTF(("csefind failed\n"));
+				crypt_result->status = EINVAL;
+				goto bail;
+			}
+
+			if (crp->crp_etype != 0) {
+				crypt_result->status = crp->crp_etype;
+				goto bail;
+			}
+
+			if (cse->error) {
+				crypt_result->status = cse->error;
+				goto bail;
+			}
+
+			if (crp->dst &&
+			    (crypt_result->status = copyout
+						(crp->uio.uio_iov[0].iov_base, 
+						crp->dst, crp->len)))
+				goto bail;
+			
+			if (crp->mac &&
+			    (crypt_result->status = copyout(crp->crp_mac, 
+					crp->mac, cse->thash->authsize)))
+				goto bail;
+bail:
+			TAILQ_REMOVE(&fcr->crp_ret_mq, crp, crp_next);
+
+			mutex_spin_exit(&crypto_mtx);
+			crypto_freereq(crp);
+			return 0;
+		}
+	}
+
+	TAILQ_FOREACH(krp, &fcr->crp_ret_mkq, krp_next) {
+		if(krp && (krp->krp_reqid == crypt_result->rid)) {
+			crypt_result[req].opaque = krp->krp_usropaque;
+			if (krp->krp_status != 0) {
+				DPRINTF(("cryptodev_key: "
+					 "krp->krp_status 0x%08x\n", 
+					 krp->krp_status));
+				crypt_result[req].status = krp->krp_status;
+				goto fail;
+			}
+
+			for (i = krp->krp_iparams; i < krp->krp_iparams 
+						+ krp->krp_oparams; i++) {
+				size = (krp->krp_param[i].crp_nbits + 7) / 8;
+				if (size == 0)
+					continue;
+				crypt_result[req].status = copyout
+						(krp->krp_param[i].crp_p, 
+						krp->crk_param[i].crp_p, size);
+				if (crypt_result[req].status) {
+					DPRINTF(("cryptodev_key: copyout oparam"
+						"%d failed, error=%d\n", 
+						i-krp->krp_iparams, 
+						crypt_result[req].status));
+					goto fail;
+				}
+			}
+fail:
+			TAILQ_REMOVE(&fcr->crp_ret_mkq, krp, krp_next);
+			mutex_spin_exit(&crypto_mtx);
+			/* not sure what to do for this */
+			/* kop[req].crk_status = krp->krp_status; */ 
+			for (i = 0; i < CRK_MAXPARAM; i++) {
+				struct crparam *kp = &(krp->krp_param[i]);
+				if (kp->crp_p) {
+					size = (kp->crp_nbits + 7) / 8;
+					KASSERT(size > 0);
+					memset(kp->crp_p, 0, size);
+					kmem_free(kp->crp_p, size);
+				}
+			}
+			pool_put(&cryptkop_pool, krp);
+			return 0;
+		}
+	}
+	mutex_spin_exit(&crypto_mtx);
+	return EINPROGRESS;			
+}
+
+static int      
+cryptof_poll(file_t *fp, int events, struct lwp *l)
+{
+	struct fcrypt *fcr = (struct fcrypt *)fp->f_data;
+
+	if (!(events & (POLLIN | POLLRDNORM))) {
+		/* only support read and POLLIN */
+		return 0;
+	}
+
+	if (TAILQ_EMPTY(&fcr->crp_ret_mq) && TAILQ_EMPTY(&fcr->crp_ret_mkq)) {
+		/* no completed requests pending,
+		 * save the poll for later (for selnotify()). */
+		selrecord(l, &fcr->sinfo);
+		return 0;
+	} else {
+		/* let the app(s) know that there are completed requests */
+		return events & (POLLIN | POLLRDNORM);
+	}
+}
+
 /*
  * Pseudo-device initialization routine for /dev/crypto
  */
diff -r -u -p opencrypto.o/cryptodev.h opencrypto/cryptodev.h
--- opencrypto.o/cryptodev.h	2008-02-03 19:35:34.000000000 -0500
+++ opencrypto/cryptodev.h	2008-03-27 01:32:44.000000000 -0400
@@ -2,6 +2,42 @@
 /*	$FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.2.2.6 2003/07/02 17:04:50 sam Exp $	*/
 /*	$OpenBSD: cryptodev.h,v 1.33 2002/07/17 23:52:39 art Exp $	*/
 
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Coyote Point Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /*
  * The author of this code is Angelos D. Keromytis ([email protected])
  *
@@ -121,6 +157,22 @@ struct session_op {
   	u_int32_t	ses;		/* returns: session # */
 };
 
+/* to support multiple session creation */
+
+struct session_n_op {
+	u_int32_t	cipher;		/* ie. CRYPTO_DES_CBC */
+	u_int32_t	mac;		/* ie. CRYPTO_MD5_HMAC */
+
+	u_int32_t	keylen;		/* cipher key */
+	void *		key;
+	int		mackeylen;	/* mac key */
+	void *		mackey;
+
+	u_int32_t	ses;		/* returns: session # */
+	int		status;
+	struct session_n_op *	next;	/* next pointer for multiple session */
+};
+
 struct crypt_op {
 	u_int32_t	ses;
 	u_int16_t	op;		/* i.e. COP_ENCRYPT */
@@ -134,6 +186,57 @@ struct crypt_op {
 	void *		iv;
 };
 
+/* to support multiple session creation */
+/*
+ *
+ * The reqid field is filled when the operation has 
+ * been accepted and started, and can be used to later retrieve
+ * the operation results via CIOCNCRYPTRET or identify the 
+ * request in the completion list returned by CIOCNCRYPTRETM.
+ *
+ * The opaque pointer can be set arbitrarily by the user
+ * and it is passed back in the crypt_result_t structure
+ * when the request completes.  This field can be used for example
+ * to track context for the request and avoid lookups in the
+ * user application.
+ */
+
+struct crypt_n_op {
+	u_int32_t	ses;
+	u_int16_t	op;		/* i.e. COP_ENCRYPT */
+#define COP_ENCRYPT	1
+#define COP_DECRYPT	2
+	u_int16_t	flags;
+#define COP_F_BATCH	0x0008		/* Dispatch as quickly as possible */
+	u_int		len;
+
+	u_int32_t	reqid;		/* request id */
+	int		status;		/* status of request -accepted or not */	
+	void		*opaque;	/* opaque pointer returned to user */
+	u_int32_t	keylen;		/* cipher key - optional */
+	void *		key;
+
+	void *		src, *dst;	/* become iov[] inside kernel */
+	void *		mac;		/* must be big enough for chosen MAC */
+	void *		iv;
+};
+
+/* CIOCNCRYPTM ioctl argument, supporting one or more asynchronous
+ * crypto_n_op operations.
+ * Each crypo_n_op will receive a request id which can be used to check its
+ * status via CIOCNCRYPTRET, or to watch for its completion in the list
+ * obtained via CIOCNCRYPTRETM.
+ */
+struct crypto_mop {
+	size_t 		count;		/* how many */
+	struct crypt_n_op *	reqs;	/* where to get them */
+};
+
+struct crypt_fnop {
+	size_t		count;
+	u_int32_t	*sesid;
+}; 
+
 #define CRYPTO_MAX_MAC_LEN	20
 
 /* bignum parameter, in packed bytes, ... */
@@ -152,6 +255,53 @@ struct crypt_kop {
 	u_int		crk_pad1;
 	struct crparam	crk_param[CRK_MAXPARAM];
 };
+
+/*
+ * Used with the CIOCNFKEYM ioctl.
+ *
+ * This structure allows the OCF to return a request id
+ * for each of the kop operations specified in the CIOCNFKEYM call.
+ * 
+ * The crk_opaque pointer can be arbitrarily set by the user
+ * and it is passed back in the crypt_result_t structure
+ * when the request completes.  This field can be used for example
+ * to track context for the request and avoid lookups in the
+ * user application.
+ */
+struct crypt_n_kop {
+	u_int		crk_op;		/* ie. CRK_MOD_EXP or other */
+	u_int		crk_status;	/* return status */
+	u_short		crk_iparams;	/* # of input parameters */
+	u_short		crk_oparams;	/* # of output parameters */
+	u_int		crk_pad1;
+	struct crparam	crk_param[CRK_MAXPARAM];
+	u_int32_t	reqid;		/* request id */
+	int		status;		/* status of request -accepted or not */
+	void		*crk_opaque;	/* opaque pointer returned to user */
+};
+
+struct crypto_mkop {
+	size_t	count;			/* how many */
+	struct crypt_n_kop *	reqs;	/* where to get them */
+};
+
+/* Asynchronous key or crypto result.
+ * Note that the status will be set in the crypt_result_t structure,
+ * not in the original crypt_kop structure (crk_status).
+ */
+struct crypt_result_t {
+	u_int32_t	rid;		/* request id */
+	u_int32_t	status;		/* status of request: 0 if successful */
+	void *		opaque;		/* Opaque pointer from the user, passed along */
+};
+
+struct cryptret_t {
+	size_t		count;		/* space for how many */
+	struct crypt_result_t *	results;	/* where to put them */
+}; 
+
+
+/* Assymetric key operations */
 #define	CRK_ALGORITM_MIN	0
 #define CRK_MOD_EXP		0
 #define CRK_MOD_EXP_CRT		1
@@ -178,6 +328,146 @@ struct crypt_kop {
 #define CRF_MOD_MULTINV		(1 << CRK_MOD_MULTINV)
 #define CRF_MOD			(1 << CRK_MOD)
 
+/**********************************************************************
+ 
+   IOCTL Request descriptions
+  
+     CRIOGET int *fd
+               Clone the fd argument to ioctl(4), yielding a new file descrip-
+               tor which can be used to create crypto sessions and request
+               crypto operations.
+
+     CIOCGSESSION struct session_op *sessp
+               Persistently bind a file descriptor returned by a previous
+               CRIOGET to a session: that is, to the chosen privacy algorithm,
+               integrity algorithm, and keys specified in sessp.  The special
+               value 0 for either privacy or integrity is reserved to indicate
+               that the indicated operation (privacy or integrity) is not
+               desired for this session.
+
+               For non-zero symmetric-key privacy algorithms, the privacy
+               algorithm must be specified in sess->cipher, the key length in
+               sessp->keylen, and the key value in the octets addressed by
+               sessp->key.
+
+               For keyed one-way hash algorithms, the one-way hash must be
+               specified in sessp->mac, the key length in sessp->mackey, and
+               the key value in the octets addressed by sessp->mackeylen.
+
+               Support for a specific combination of fused privacy  and
+               integrity-check algorithms depends on whether the underlying
+               hardware supports that combination.  Not all combinations are
+               supported by all hardware, even if the hardware supports each
+               operation as a stand-alone non-fused operation.
+
+     CIOCCRYPT struct crypt_op *cr_op
+               Request a symmetric-key (or unkeyed hash) operation.  The file
+               descriptor argument to ioctl(4) must have been bound to a valid
+               session.  To encrypt, set cr_op->op to COP_ENCRYPT.  To
+               decrypt, set cr_op->op to COP_DECRYPT.  The field cr_op->len
+               supplies the length of the input buffer; the fields cr_op->src,
+               cr_op->dst, cr_op->mac, cr_op->iv supply the addresses of the
+               input buffer, output buffer, one-way hash, and initialization
+               vector, respectively.
+
+     CIOCNCRYPTM struct crypto_mop *cr_mop
+               This is the asynchronous version of CIOCCRYPT, which allows 
+	       multiple symmetric-key (or unkeyed hash) operations to be
+	       started (see CIOCRYPT above for the details for each operation).
+	       The cr_mop->count field specifies the number of operations
+	       provided in the cr_mop->reqs array.
+
+	       Each operation is assigned a unique request id returned in the
+	       cr_mop->reqs[n].reqid field.
+
+	       Each operation can accept an opaque value from the user to
+	       be passed back to the user when the operation completes 
+	       (e.g. to track context for the request).  The opaque field
+	       is cr_mop->reqs[n].opaque.
+
+	       If a problem occurs with starting any of the operations then
+	       that operation's cr_mop->reqs[n].status field is filled with
+	       the error code.  The failure of an operation does not prevent
+	       the other operations from being started.
+
+
+     CIOCFSESSION u_int32_t *session
+               Destroys the specified /dev/crypto session associated with the
+	       file-descriptor argument.
+
+     CIOCFNSESSION struct crypt_fnop *cr_fnop
+               Destroys the cr_fnop->count /dev/crypto sessions specified by
+	       the crypt_fnop array of session identifiers.
+
+   Asymmetric-key commands
+     CIOCASSYMFEAT int *feature_mask
+               Returns a bitmask of supported asymmetric-key operations.  Each
+               of the above-listed asymmetric operations is present if and
+               only if the bit position numbered by the code for that opera-
+               tion is set.  For example, CRK_MOD_EXP is available if and only
+               if the bit (1 << CRK_MOD_EX) is set.
+
+     CIOCFKEY struct crypt_kop *kop
+               Performs an asymmetric-key operation from the list above.  The
+               specific operation is supplied in kop->crk_op; final status for
+               the operation is returned in kop->crk_status.  The number of
+               input arguments and the number of output arguments is specified
+               in kop->crk_iparams and kop->crk_iparams, respectively.  The
+               field crk_param[] must be filled in with exactly
+               kop->crk_iparams + kop->crk_oparams arguments, each encoded as
+               a struct crparam (address, bitlength) pair.
+
+     CIOCNFKEYM struct crypt_mkop *mkop
+               This is the asynchronous version of CIOCKEY, which starts one 
+	       or more key operations.
+	       mkop->count specifies the number of key operations in the
+	       mkop->reqs array.
+
+	       Each operation is assigned a unique request id returned in the
+	       mkop->reqs[n].reqid field.
+
+	       Each operation accepts an opaque value from the user to
+	       be passed back to the user when the operation completes 
+	       (e.g. to track context for the request).  The opaque field
+	       is mkop->reqs[n].crk_opaque.
+
+	       If a problem occurs with starting any of the operations then
+	       that operation's mkop->reqs[n].status field is filled with
+	       the error code.  The failure of an operation does not prevent
+	       the other operations from being started.
+
+   Asynchronous status commands
+     select() or poll() can be used to determine when /dev/crypto has completed
+     operations ready to be retrieved.
+
+     CIOCNCRYPTRET struct crypt_result_t *cres
+               Check for the status of the request specified by cres->rid.
+
+	       The cres->status field is set as follows:
+	         0 - the request has completed, and its results have been 
+		 copied out to the original crypt_op or crypt_kop structure
+		 used to start the request.  The copyout takes place during
+		 this ioctl, so the calling process must be the process that
+		 started the request.
+
+		 EINPROGRESS - the request has not yet completed.
+
+		 EINVAL - the request was not found.
+
+		 Other values indicate a problem during the processing of 
+		 the request.
+
+     CIOCNCRYPTRETM struct cryptret_t *cret
+               Retreive a number of completed requests.  This ioctl accepts
+	       a count and an array, and fills the array with up to count
+	       completed requests.  The array entries are described above
+	       in the CIONCRYPTRET ioctl.
+
+	       The cret->results[n].rid fields filled by this ioctl call.
+	       The results may be mixed crypt_op and crypt_kop operations.
+
+**********************************************************************/
+
 /*
  * done against open of /dev/crypto, to get a cloned descriptor.
  * Please use F_SETFD against the cloned descriptor.
@@ -189,6 +479,12 @@ struct crypt_kop {
 #define	CIOCFSESSION	_IOW('c', 102, u_int32_t)
 #define CIOCCRYPT	_IOWR('c', 103, struct crypt_op)
 #define CIOCKEY		_IOWR('c', 104, struct crypt_kop)
+#define	CIOCNSESSION	_IOWR('c', 106, struct session_n_op)
+#define CIOCNCRYPTM	_IOWR('c', 107, struct crypto_mop)
+#define CIOCNFKEYM	_IOWR('c', 108, struct crypto_mkop)
+#define CIOCFNSESSION	_IOW('c', 109, struct crypt_fnop)
+#define CIOCNCRYPTRETM	_IOWR('c', 110, struct cryptret_t)
+#define CIOCNCRYPTRET	_IOWR('c', 111, struct crypt_result_t)
 
 #define CIOCASYMFEAT	_IOR('c', 105, u_int32_t)
 
@@ -257,9 +553,16 @@ struct cryptodesc {
 
 /* Structure describing complete operation */
 struct cryptop {
-	TAILQ_ENTRY(cryptop) crp_next;
-
+	union {
+		TAILQ_ENTRY(cryptop) crp_tnext;
+		SLIST_ENTRY(cryptop) crp_lnext;
+	}		crp_qun;
+#define	crp_next crp_qun.crp_tnext	/* XXX compat */
 	u_int64_t	crp_sid;	/* Session ID */
+	
+	u_int32_t	crp_reqid;	/* request id */
+	void *		crp_usropaque;	/* Opaque pointer from user, passed along */
+
 	int		crp_ilen;	/* Input data total length */
 	int		crp_olen;	/* Result total length */
 
@@ -293,6 +596,15 @@ struct cryptop {
 	void *		crp_mac;
 	struct timespec	crp_tstamp;	/* performance time stamp */
 	kcondvar_t	crp_cv;
+	struct fcrypt 	*fcrp;
+	void * 		dst;
+	void *		mac;
+	u_int		len;
+	u_char		tmp_iv[EALG_MAX_BLOCK_LEN];
+	u_char		tmp_mac[CRYPTO_MAX_MAC_LEN];
+	
+	struct iovec	iovec[1];
+	struct uio	uio;
 };
 
 #define CRYPTO_BUF_CONTIG	0x0
@@ -308,7 +620,14 @@ struct cryptop {
 #define	CRYPTO_HINT_MORE	0x1	/* more ops coming shortly */
 
 struct cryptkop {
-	TAILQ_ENTRY(cryptkop) krp_next;
+	union {
+		TAILQ_ENTRY(cryptkop) krp_tnext;
+                SLIST_ENTRY(cryptkop) krp_lnext;
+        }               krp_qun;
+#define krp_next krp_qun.krp_tnext	/* XXX compat */
+
+	u_int32_t	krp_reqid;	/* request id */
+	void *		krp_usropaque;	/* Opaque pointer from user, passed along */
 
 	u_int		krp_op;		/* ie. CRK_MOD_EXP or other */
 	u_int		krp_status;	/* return status */
@@ -319,6 +638,8 @@ struct cryptkop {
 	int		(*krp_callback)(struct cryptkop *);
 	int		krp_flags;	/* same values as crp_flags */
 	kcondvar_t	krp_cv;
+	struct fcrypt 	*fcrp;
+	struct crparam	crk_param[CRK_MAXPARAM];
 };
 
 /* Crypto capabilities structure */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.