tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

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



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.                      <tls%coyotepoint.com@localhost>
Millerton, NY, USA
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 
(angelos%cis.upenn.edu@localhost)
  *
@@ -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 
(angelos%cis.upenn.edu@localhost)
  *
@@ -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 */


Home | Main Index | Thread Index | Old Index