[kernel] ocf: move all stuff into files, and fix build error on .25
authorGabor Juhos <juhosg@openwrt.org>
Wed, 19 Nov 2008 12:25:39 +0000 (12:25 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Wed, 19 Nov 2008 12:25:39 +0000 (12:25 +0000)
SVN-Revision: 13288

54 files changed:
target/linux/generic-2.6/files/crypto/ocf/ChangeLog [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/Config.in [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/Kconfig [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/criov.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/crypto.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/cryptodev.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/cryptodev.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/cryptosoft.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/environment.mk [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_asym.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_common.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_ocf.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_sym.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/hifn7751.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/hifn7751reg.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/hifn7751var.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/hifnHIPP.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/hifnHIPPreg.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/hifn/hifnHIPPvar.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ixp4xx/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ixp4xx/ixp4xx.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ocf-bench.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ocf-compat.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ocfnull/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/ocfnull/ocfnull.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/pasemi/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/pasemi/pasemi.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/pasemi/pasemi_fnu.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/random.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/rndtest.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/rndtest.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/md5.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/md5.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/safe.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/safereg.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/safevar.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/sha1.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/safe/sha1.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/talitos/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/talitos/talitos.c [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/talitos/talitos_dev.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/talitos/talitos_soft.h [new file with mode: 0644]
target/linux/generic-2.6/files/crypto/ocf/uio.h [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/970-ocf_kbuild_integration.patch [deleted file]
target/linux/generic-2.6/patches-2.6.25/971-ocf_20080917.patch
target/linux/generic-2.6/patches-2.6.26/970-ocf_kbuild_integration.patch [deleted file]
target/linux/generic-2.6/patches-2.6.26/971-ocf_20080917.patch
target/linux/generic-2.6/patches-2.6.27/970-ocf_kbuild_integration.patch [deleted file]
target/linux/generic-2.6/patches-2.6.27/971-ocf_20080917.patch

diff --git a/target/linux/generic-2.6/files/crypto/ocf/ChangeLog b/target/linux/generic-2.6/files/crypto/ocf/ChangeLog
new file mode 100644 (file)
index 0000000..e913ef2
--- /dev/null
@@ -0,0 +1,1960 @@
+2008-09-18 01:27  davidm
+
+       * Makefile, README, README.sglinux,
+       patches/linux-2.6.26-natt.patch, patches/linux-2.6.26-ocf.patch,
+       patches/openssl-0.9.8g.patch, patches/openssl-0.9.8i.patch: 
+       
+       Updates for a new OCF release with openssl-0.9.8i and linux-2.6.26
+       support.
+
+2008-09-18 00:19  davidm
+
+       * Config.in, Kconfig, Makefile, ep80579/Makefile,
+       ep80579/environment.mk, ep80579/icp_asym.c, ep80579/icp_common.c,
+       ep80579/icp_ocf.h, ep80579/icp_sym.c,
+       ep80579/linux_2.6_kernel_space.mk: 
+       
+       A new driver from Intel for their Intel QuickAssist enabled EP80579
+       Integrated Processor Product Line.
+       
+       Adrian Hoban  Brad Vrabete
+       
+
+2008-07-25 01:01  gerg
+
+       * ocf-compat.h: 
+       
+       From linux-2.6.26 onwards there is now a linux/fdtable.h include
+       that contains the file_fdtable() definition.
+
+2008-07-05 01:20  davidm
+
+       * Makefile, patches/linux-2.6.25-natt.patch,
+       patches/linux-2.6.25-ocf.patch: 
+       
+       A new ocf-linux release and some patches to send to the OS guys.
+
+2008-07-03 21:21  davidm
+
+       * crypto.c: 
+       
+       Clean up a some possible deadlock/busy wait issues with
+       locking/sleeping.  This has greatly improved openswan 2.6.14
+       reliability ;-)
+       
+       Make more of our state available in /sys for debugging.
+
+2008-06-23 20:38  davidm
+
+       * Config.in, Kconfig: 
+       
+       Some settings should be bool's John Gumb 
+
+2008-05-28 03:43  philipc
+
+       * ixp4xx/ixp4xx.c:  Revert previous checkin since the
+       callbacks are meant to complete the crypto request.  Before
+       reverting this, CONFIG_DEBUG_SLAB gives: slab error in
+       verify_redzone_free(): cache `ixp4xx_q': double free detected when
+       trying to ssh to the device.
+
+2008-04-27 19:31  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       We were not completing a crypto request under some error
+       conditions.
+
+2008-04-02 01:51  davidm
+
+       * talitos/talitos.c: 
+       
+       This patch is for crypto/ocf/talitos for use on linux 2.6.23.  It
+       is applied to the ocf-linux-20071215 release.
+       
+       Signed-off-by: Lee Nipper 
+
+2008-02-29 00:43  davidm
+
+       * crypto.c, ocf-compat.h, ixp4xx/ixp4xx.c: 
+       
+       freshen  up the 2.4 support,  some recent OCF changes and openswan
+       changes are not that old-os friendly.
+       
+       Force OCF to select HW/SW,  otherwise it may get stuck on the first
+       device.  This change means we will favour HW over SW,  but we will
+       use both as required.  Passing in a crid of 0 to crypto_newsession
+       effectively meant we were stuck on the first device registered with
+       OCF,  not good.  This only applied to ipsec,  cryptodev already did
+       the right thing.
+
+2008-01-31 07:37  gerg
+
+       * hifn/hifn7751.c: 
+       
+       The linux-2.6.24 modules build fails if the pci ID table doesn't
+       have a NULL entry at the end. So add one.
+
+2008-01-29 09:16  gerg
+
+       * cryptosoft.c, ocf-compat.h: 
+       
+       Added some compatability macros for scatterlist changes from 2.6.24
+       onwards.
+
+2007-12-16 07:31  davidm
+
+       * Makefile: 
+       
+       missed an openssl patch name change
+
+2007-12-16 07:27  davidm
+
+       * Makefile, README, README.sglinux, patches/linux-2.6.23-ocf.patch,
+       patches/openssl-0.9.8e.patch, patches/openssl-0.9.8g.patch,
+       patches/ssl.patch: 
+       
+       updates for a new ocf release and associated bits
+
+2007-12-16 06:36  davidm
+
+       * crypto.c: 
+       
+       Be very careful what you do while potentially in an driver unload
+       state or we will call through NULL pointers.
+       
+       Reported by Nawang Chhetan .
+
+2007-12-14 22:32  davidm
+
+       * cryptodev.c: 
+       
+       Add in an unlock_ioctl when available to help SMP systems a lot. 
+       Otherwise all ioctls get a BKL :-(
+       
+       Problem found by Egor N. Martovetsky 
+
+2007-12-14 18:29  davidm
+
+       * cryptosoft.c: 
+       
+       reformat the alg table to make it easier to read.
+
+2007-12-14 18:29  davidm
+
+       * crypto.c: 
+       
+       Fix more driver locking/sleeping bugs report by Nawang Chhetan
+       
+
+2007-12-12 21:36  davidm
+
+       * Config.in, Kconfig, Makefile, pasemi/Makefile, pasemi/pasemi.c,
+       pasemi/pasemi_fnu.h: 
+       
+       Here I'm including my PA Semi driver patch to OCF.  Please consider
+       it for inclusion into next OCF release.
+       
+       Egor N. Martovetsky 
+
+2007-12-05 00:37  davidm
+
+       * patches/: linux-2.4.35-ocf.patch, linux-2.6.22-ocf.patch: 
+       
+       More correct count setting if we get a signal
+       
+       Adrian Hoban 
+
+2007-12-05 00:02  davidm
+
+       * random.c: 
+       
+       OCF has a static array for holding random data. The random number
+       generator I have can write directly into physically contiguous
+       memory. Static memory comes from the heap and isn't physically
+       contiguous. I could use kmalloc'd memory and then copy into the OCF
+       static buf but I'd like to avoid a memory copy. The following patch
+       (Physically_Contig_Rand.patch) allows me to avoid a memory copy and
+       should not impact the other OCF drivers:
+       
+       Adrian Hoban 
+
+2007-12-05 00:01  davidm
+
+       * Kconfig: 
+       
+       Fix a typo in the Kconfig
+
+2007-11-23 19:15  davidm
+
+       * talitos/talitos_dev.h: 
+       
+       fix the DPRINTF macro so that it actually compiles.
+
+2007-11-22 19:41  davidm
+
+       * ocf-compat.h, talitos/talitos.c, talitos/talitos_dev.h: 
+       
+       Various updates to get talitos compiling and work on real-world (ie
+       ubuntu) kernels.
+
+2007-11-08 02:21  davidm
+
+       * crypto.c: 
+       
+       keep and eye on us being completely blocked.  If we have Q's to
+       process, but all the requests are blocked,  sleep.  We do not want
+       to busy loop until a driver unblocks as it uses valuable CPU
+       resources that could be doing something much more important ;-)
+
+2007-11-07 19:04  davidm
+
+       * hifn/hifn7751.c: 
+       
+       hifn driver was failing to unblock itself under some "out of
+       resources" conditions.  It would return ERESTART to signal it was
+       full but never call crypto_unblock to start things moving again.
+
+2007-11-06 02:09  davidm
+
+       * hifn/hifn7751.c: 
+       
+       Remove some bogus trace left in the driver for the overflow (too
+       busy) case.
+
+2007-10-12 21:10  gerg
+
+       * crypto.c, ixp4xx/ixp4xx.c: 
+       
+       Fix up use of kmem_cache_create() - it takes one less argument in
+       2.6.23 onwards.
+
+2007-10-03 02:41  gerg
+
+       * ixp4xx/Makefile: 
+       
+       The directory locations for includes in CSR-2.4 is different.  Need
+       to modify the CFLAGS accordingly if using CSR-2.4.
+
+2007-09-22 00:39  philipc
+
+       * ixp4xx/Makefile:  linux 2.4 make dep was failing.  This is
+       a quick fix to get it building, need to double check this.
+
+2007-09-19 00:13  mmccreat
+
+       * Config.in:  Add config option CONFIG_OCF_IXP4XX_SHA1_MD5,
+       that enables SHA1 and MD5 hashing to be done by the IXP4xx crypto
+       accelerator (although it is much slower than using cryptosoft).
+
+2007-09-18 21:45  mmccreat
+
+       * Makefile, random.c:  - Force the inclusion of autoconf.h,
+       which contains #defines for CONFIG_xxx   options for OCF.  -
+       Removing additional -D option, now that we are including the
+       CONFIG_xxx   #defines.
+
+2007-09-18 21:44  mmccreat
+
+       * Kconfig:  Add config option CONFIG_OCF_IXP4XX_SHA1_MD5,
+       that enables SHA1 and MD5 hashing to be done by the IXP4xx crypto
+       accelerator (although it is much slower than using cryptosoft).
+
+2007-09-18 21:37  mmccreat
+
+       * cryptodev.h:  The CRYPTO_MAX_DATA_LEN limit should be
+       0xFFFF ie 64K - 1.
+
+2007-09-18 21:19  mmccreat
+
+       * ixp4xx/ixp4xx.c:  - Rework the code so that the correct IXP
+       function, ixCryptoAccHashPerform(), is   used to calculate SHA1 and
+       MD5 hashes.    NB: The performance of using the IXP4xx hardware is
+       really, really poor    compared to using cryptosoft (and the kernel
+       crypto).  - Only support SHA1 and MD5 hashing if the
+       CONFIG_OCF_IXP4XX_SHA1_MD5 is   enabled.
+
+2007-08-30 21:42  davidm
+
+       * Makefile: 
+       
+       do not archive build files in the crypto-tools archive
+
+2007-08-22 19:19  mmccreat
+
+       * cryptodev.c:  Fix up the checking for key lengths, when the
+       key can be of unlimited size.
+
+2007-08-16 01:50  davidm
+
+       * Makefile: 
+       
+       Better 2.4 compat for "make dep" now working with fastdep.
+
+2007-07-28 08:25  davidm
+
+       * Makefile, README, README.sglinux, patches/crypto-tools.patch,
+       patches/linux-2.4.29-ocf.patch, patches/linux-2.4.35-ocf.patch,
+       patches/linux-2.6.11-ocf.patch, patches/linux-2.6.22-ocf.patch,
+       patches/ssl.patch: 
+       
+       Update all the patches and put the patch making target back into
+       the Makefile.
+
+2007-07-28 08:25  davidm
+
+       * hifn/hifn7751.c: 
+       
+       fix an unused variable warning when HARVESTING is disabled
+
+2007-07-27 21:33  davidm
+
+       * hifn/hifn7751.c, ixp4xx/ixp4xx.c, safe/safe.c, talitos/talitos.c:
+       
+       
+       Remove all the random code if OCF does not have radom harvesting
+       enabled.
+
+2007-07-26 00:36  davidm
+
+       * Kconfig, hifn/hifnHIPP.c, hifn/hifnHIPPvar.h: 
+       
+       Changes to get the hifn HIPP stub driver to build.
+
+2007-07-25 21:25  davidm
+
+       * Makefile, hifn/Makefile, hifn/hifnHIPP.c, hifn/hifnHIPPreg.h,
+       hifn/hifnHIPPvar.h, ixp4xx/Makefile, ocfnull/Makefile,
+       safe/Makefile, talitos/Makefile: 
+       
+       Bring in the hifnHIPP driver written by Xelerance.  This is the
+       super hifn chip with full protocol offload.
+       
+       Switch to much more traditional Makefile/subdir building.  The
+       Makefiles are nicer now,  but still not beautiful,  2.6 and 2.4
+       capable builds result in a certain amount of uglyiness.
+
+2007-07-24 21:46  davidm
+
+       * cryptodev.c: 
+       
+       Clean up all the driver id checking and session management so
+       adding/removing drivers all continues to run cleanly.
+
+2007-07-24 20:14  davidm
+
+       * talitos/talitos.c: 
+       
+       From: Ahsan Kabir 
+       
+       less than .1% packet corruption was detected using the talitos
+       driver. It turns out we don't need the cipher iv out len/ptr field
+       to do ESP IPsec. Therefore we set the len field as 0, which tells
+       the SEC not to do anything with this len/ptr field.
+       
+       Signed-off-by: Ahsan Kabir 
+       Signed-off-by: Kim Phillips 
+
+2007-07-24 08:25  davidm
+
+       * cryptosoft.c, ocf-bench.c, hifn/hifn7751.c, ixp4xx/ixp4xx.c,
+       safe/safe.c, talitos/talitos.c: 
+       
+       Switch the remaining GFP_ATOMIC to the newer and not deprecated
+       SLAB_ATOMIC
+
+2007-07-23 22:16  mmccreat
+
+       * ixp4xx/ixp4xx.c:  Add missing ";" from end of dprintk()
+       call!
+
+2007-07-21 01:16  davidm
+
+       * ocf-compat.h, rndtest.c, hifn/hifn7751.c, safe/safe.c: 
+       
+       pci_register_driver is nothing like it is depending on the kernel,
+       so we need a compat function to fix it up for all kernels before
+       2.6.10, and in different ways for older and not so older versions.
+
+2007-07-20 21:54  davidm
+
+       * safe/safe.c: 
+       
+       Make the debug macro ';' safe so you do not get compiler warnings
+
+2007-07-20 21:53  davidm
+
+       * talitos/: talitos.c, talitos_dev.h, talitos_soft.h: 
+       
+       update to the latest FreeBSD driver structure and fix up the code
+       as required.
+
+2007-07-20 03:07  davidm
+
+       * rndtest.c: 
+       
+       more headers needed to compile on 2.4
+
+2007-07-20 03:00  davidm
+
+       * cryptosoft.c: 
+       
+       Put in the 2.4 stubs to support compression
+
+2007-07-20 02:53  davidm
+
+       * crypto.c, ocf-compat.h: 
+       
+       move some more compat stuff into the compat header.
+
+2007-07-20 02:47  davidm
+
+       * talitos/talitos.c: 
+       
+       support of_platform_driver for newer, ARCH=powerpc based kernels. 
+       Signed-off-by: Kim Phillips 
+
+2007-07-20 02:46  davidm
+
+       * talitos/talitos.c: 
+       
+       From: Ahsan Kabir 
+       
+       When Talitos completes job both the channel and execution unit are
+       capable of generating interrupts.  Talitos used to take two
+       interrupts per request - one for channel completion and the other
+       for execution unit completion. This patch ensures that Talitos
+       takes interrupt only for channel completion. Execution unit will
+       generate interrupt only when there is error and the error
+       interrupts for execution units are not masked.
+       
+       Signed-off-by: Ahsan Kabir 
+       Signed-off-by: Kim Phillips 
+
+2007-07-20 02:37  davidm
+
+       * cryptodev.c: 
+       
+       Unless the user specifies,  select from both HW and SW.
+       
+       Clean up some debug to report the actual ioctl name.
+       
+       Compiler warning on newer compilers.
+
+2007-07-20 02:35  davidm
+
+       * cryptodev.h: 
+       
+       moved dprintk to the compat code,  seemed nicer in there.
+
+2007-07-20 02:35  davidm
+
+       * rndtest.c: 
+       
+       Need to clean up some warnings etc,  more includes
+
+2007-07-20 02:34  davidm
+
+       * ocf-compat.h, hifn/hifn7751.c, safe/safe.c: 
+       
+       new shared IRQ flags for 2.6.22 and a safer version of the debug
+       macro
+
+2007-07-20 00:52  davidm
+
+       * cryptosoft.c: 
+       
+       Implement compression based on the code from the openswan guys.
+
+2007-07-20 00:52  davidm
+
+       * criov.c: 
+       
+       Fix compiler warning on non-value returning void func.
+
+2007-07-18 22:55  davidm
+
+       * hifn/hifn7751.c, safe/safe.c: 
+       
+       Use pci_register_driver rather than pci_module_init. 
+       pci_module_init has been dropped in 2.6.22 yet pci_register_driver
+       has always existed and used to do some crazy hotplug junk.
+
+2007-07-18 21:55  gerg
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Added a missing ";" at the end of the ixp_kproces() prototype.  It
+       is IXP465 specific, only showed up when generateing for SG720.
+
+2007-07-17 00:37  davidm
+
+       * Makefile, cryptodev.c, random.c, rndtest.c, hifn/hifn7751.c,
+       ocfnull/ocfnull.c, safe/safe.c: 
+       
+       Fixup all the debug support for 2.4 kernels,  clean up the entropy
+       harvester to be far more robust.
+
+2007-07-14 02:19  davidm
+
+       * talitos/talitos.c: 
+       
+       Old patch that had not been applied Kim Phillips
+       
+
+2007-07-14 01:12  davidm
+
+       * Config.in, Kconfig, Makefile, cryptodev.c, cryptodev.h, random.c,
+       syscall.h: 
+       
+       Finally ditched all the syscall stuff.  You can now enable/disable
+       the random harvestor.  Pulled in most of random.c from openswan
+       project and fixed some obvious bugs (that were always there).
+
+2007-07-13 21:59  davidm
+
+       * ocf-compat.h: 
+       
+       Better error printing and checking for drivers
+
+2007-07-13 21:56  davidm
+
+       * cryptosoft.c: 
+       
+       Fix some incorrect debug (reporting wrong error type)
+
+2007-07-13 21:55  davidm
+
+       * hifn/hifn7751.c, safe/safe.c: 
+       
+       Make the code more similar to Free-BSD by reverting to the same
+       debug macros
+
+2007-07-13 21:53  davidm
+
+       * ocfnull/ocfnull.c: 
+       
+       Fix up the null driver to work again in the new framework.
+
+2007-07-06 23:54  mmccreat
+
+       * cryptodev.c, cryptodev.h, cryptosoft.c:  - Update OCF to
+       work with new Crypto API introduced in 2.6.19 kerneli, and add
+       macros so it work with older kernels.  - Add support for SHA256,
+       SHA384 and SHA512 HASH and HMAC algorithms.  - Cryptosoft: Only
+       register algorithms that the kernel has implementations for.
+
+2007-07-03 19:52  davidm
+
+       * Kconfig, README, README.sglinux, criov.c, crypto.c, cryptodev.c,
+       cryptodev.h, cryptosoft.c, ocf-bench.c, ocf-compat.h, random.c,
+       rndtest.c, uio.h, hifn/hifn7751.c, hifn/hifn7751reg.h,
+       hifn/hifn7751var.h, ixp4xx/ixp4xx.c, ocfnull/ocfnull.c,
+       safe/safe.c, safe/safevar.h, talitos/talitos.c: 
+       
+       Updated OCF to the lastest FreeBSD version.
+       
+       There was a lot of change in here,  some of which will help FIP's,
+       some which won't.
+       
+       Did lots of cleaning and diff reduction against the freebsd code. 
+       Still more cleaning to do.
+
+2007-06-01 21:58  gerg
+
+       * Config.in: 
+       
+       Put the regular old Config.in back, needed for puclic releases.
+
+2007-06-01 21:58  gerg
+
+       * Kconfig: 
+       
+       Change the CONFIG_OCF_IXP400 dependencies to be the same as they
+       where in the Config.in file.
+
+2007-05-28 21:40  gerg
+
+       * Config.in, Kconfig: 
+       
+       Switch all module configuration over to new style Kconfigs.
+
+2007-05-24 18:49  davidm
+
+       * cryptodev.c, random.c: 
+       
+       Work around some problems on redhat systems with errno redefinition
+
+2007-04-30 21:09  gerg
+
+       * cryptosoft.c: 
+       
+       The CRYPTO_TFM_MODE_ family of defines no longer exists from 2.6.21
+       onwards. As far as I can tell you don't need to pass it to the
+       crypto_alloc_tfm() function anymore.
+       
+       So define it to be 0 if it doesn't exist.
+
+2007-04-03 02:13  gerg
+
+       * syscall.h: 
+       
+       Added syscall macros for SH architecture. Just temporary, 'till
+       Dave fixes the OCF code to not use syscalls from the modules :-)
+
+2007-02-16 23:10  davidm
+
+       * syscall.h: 
+       
+       ensure the temprary 2.6 fix doesn't break 2.4
+
+2007-02-07 22:23  gerg
+
+       * cryptodev.c, random.c, syscall.h: 
+       
+       Temporary fix for new 2.6 kernels no longer defining in-kernel
+       system call functions. Define them locally for now until we fix
+       properly.
+
+2007-02-07 03:10  gerg
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Changes to support the different INIT_WORK() mechanism from kernels
+       2.6.20 onwards.
+
+2007-02-06 02:38  gerg
+
+       * crypto.c: 
+       
+       Cleaned up use of kmem_cache_t and use of SLAB_ATOMIC.
+
+2006-12-05 20:50  cpascoe
+
+       * hifn/hifn7751.c, safe/safe.c, talitos/talitos.c: 
+       
+       Remove pt_regs from OCF interrupt handlers for 2.6.19+
+
+2006-12-02 03:36  gerg
+
+       * criov.c, crypto.c, cryptodev.c, cryptosoft.c, ocf-bench.c,
+       random.c, rndtest.c, hifn/hifn7751.c, ixp4xx/ixp4xx.c,
+       ocfnull/ocfnull.c, safe/safe.c, talitos/talitos.c: 
+       
+       Can no longer include linux/config.h as of 2.6.19 kernels.  Need to
+       conditionally include it based on AUTOCONF_INCLUDED not being
+       defined.
+
+2006-10-13 21:52  cpascoe
+
+       * random.c: 
+       
+       Remove another race condition that may result in us running more
+       than one random thread if modules are reloaded during heavy system
+       load.
+
+2006-10-13 21:18  cpascoe
+
+       * random.c: 
+       
+       - Permit delivery of SIGKILL to the random thread.  - Do not exit
+       prematurely if poll() is interrupted.  - Improve exit conditions so
+       that we quit immediately, rather than loop   infinitely, if the
+       last RNG source is removed while we are trying to   fill our
+       buffer.
+
+2006-10-03 20:28  cpascoe
+
+       * crypto.c, crypto.c:  AutoMerged
+       >
+       > Zero the empty half of "new driver" buffer, and not past the end
+       of the old
+       > buffer that we are about to free.
+
+2006-10-03 20:28  cpascoe
+
+       * crypto.c: 
+       
+       Zero the empty half of "new driver" buffer, and not past the end of
+       the old buffer that we are about to free.
+
+2006-08-25 23:57  davidm
+
+       * cryptosoft.c: 
+       
+       Do not print errors for failed ALG requests unless debugging
+
+2006-07-14 21:44  davidm
+
+       * cryptodev.h: 
+       
+       2.6.11 and earlier did not have the files_fdtable macro.
+
+2006-06-21 21:26  gerg
+
+       * cryptodev.h, hifn/hifn7751.c, ocfnull/ocfnull.c, safe/safe.c,
+       talitos/talitos.c: 
+       
+       Fixed up more occurrances of MODULE_PARM() needing to be converted
+       to module_param() (as of 2.6.17 and onwards).
+
+2006-06-21 00:28  gerg
+
+       * cryptosoft.c: 
+       
+       Change use of MODULE_PARM to module_param() for 2.6.17+ kernels.
+
+2006-06-20 22:13  gerg
+
+       * crypto.c, cryptodev.c, cryptodev.h, ocf-bench.c, ixp4xx/ixp4xx.c:
+       
+       
+       As of 2.6.17 and onwards module_param is used in place of
+       MODULE_PARM.
+
+2006-06-06 00:31  gerg
+
+       * Makefile: 
+       
+       Fix Makefile to find includes is using CSR-2.1.
+
+2006-05-31 01:44  gerg
+
+       * cryptodev.h: 
+       
+       The vars "crypto_usercrypto", "crypto_userasymcrypto" are declared
+       as extern in the header file, but static in the c file. I guessed
+       that they should probably be truely static, so removed the extern
+       declarations from the header.
+
+2006-05-25 21:06  davidm
+
+       * talitos/talitos.c: 
+       
+       This fixes a situation that I never provably experienced, where a
+       descriptor in memory may be reserved within the proper lock, and
+       freed immediately after, only for a few cycles, right outside the
+       lock.  Kim Phillips 
+
+2006-05-15 19:49  davidm
+
+       * criov.c, crypto.c, cryptodev.c, cryptodev.h, cryptosoft.c,
+       ocf-bench.c, random.c, rndtest.c, uio.h, ixp4xx/ixp4xx.c: 
+       
+       Remove the "all rights reserved" from the Intel copyrights.
+
+2006-05-12 21:19  davidm
+
+       * Config.in, Kconfig, Makefile, cryptodev.c, ocf-bench.c,
+       ocfnull/ocfnull.c: 
+       
+       Add in a null OCF driver that does nothing at all,  useful for
+       measuring the cost of various parts of the ipsec stack.
+
+2006-05-12 21:17  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       make sure we do not overwrite a correctly set error type.
+
+2006-05-12 06:52  davidm
+
+       * crypto.c: 
+       
+       Fix a problem where a driver would return ERESTART (full) but then
+       unblock itself before the upper layer had marked it as blocked. 
+       This caused the code to get stuck in crypto_proc and process no
+       more requests.
+
+2006-05-12 06:47  davidm
+
+       * cryptosoft.c: 
+       
+       Implement CRD_F_KEY_EXPLICIT for cryptosoft so keys can be changed
+       on an active session.
+
+2006-05-10 20:09  davidm
+
+       * README, criov.c, crypto.c, cryptodev.h, cryptosoft.c,
+       ocf-bench.c, random.c, rndtest.c, uio.h, hifn/hifn7751.c,
+       ixp4xx/ixp4xx.c, safe/safe.c, safe/safevar.h: 
+       
+       update email addresses and other house cleaning
+
+2006-05-10 20:08  davidm
+
+       * cryptodev.c: 
+       
+       pull in better error checking from openswan modifications
+
+2006-05-10 19:11  davidm
+
+       * cryptosoft.c: 
+       
+       Fix an unused variable warning when various options are disabled.
+
+2006-05-10 19:10  davidm
+
+       * cryptodev.h: 
+       
+       Add support for 2.4 kernels for the new FD cloning operation
+
+2006-05-09 19:48  davidm
+
+       * hifn/hifn7751.c: 
+       
+       remove the hifn 7855 support,  this driver will never work with
+       that chip.
+
+2006-05-08 23:34  davidm
+
+       * hifn/hifn7751var.h: 
+       
+       Contiguous buffer support so that ocf-bench can run properly.
+
+2006-05-05 23:21  davidm
+
+       * hifn/hifn7751.c: 
+       
+       Add in contiguous buffer support so that ocf-bench and run on the
+       driver.
+
+2006-05-05 23:14  davidm
+
+       * ocf-bench.c: 
+       
+       Our requests were out of order,  need to do crypto then auth on
+       encrypt requests.  Some drivers enforce this.
+
+2006-05-04 23:21  davidm
+
+       * crypto.c: 
+       
+       Do not run "newsession" with lock,  since newsession may sleep on
+       some targets.  Handle the accounting so that things are not pulled
+       from underneath us.
+
+2006-05-04 23:20  davidm
+
+       * cryptodev.c: 
+       
+       Switch to a less optimal (marginally) solution for creating a new
+       fd that appears to work in far more versions of the kernel
+       including 64bit versions.
+
+2006-05-04 18:54  davidm
+
+       * ocf-bench.c: 
+       
+       Turn off the IXP access lib benchmarking by default as most people
+       don't have it.
+       
+       Paul Wouters 
+
+2006-04-01 08:23  davidm
+
+       * Makefile: 
+       
+       Remove more temp files when cleaning
+
+2006-04-01 08:12  davidm
+
+       * hifn/hifn7751reg.h: 
+       
+       7855 PCI id's as yet untested
+
+2006-04-01 08:08  davidm
+
+       * hifn/hifn7751.c: 
+       
+       add PCI id's for the 7855 and AES support,  card is untested still
+       as it requires 128MB of PCI memory !
+
+2006-03-31 08:38  davidm
+
+       * README.sglinux: 
+       
+       small update to instructions with corrected patch name
+
+2006-03-31 00:23  davidm
+
+       * Config.in: 
+       
+       Add the Talitos driver to the 2.4 config,  even though it probably
+       won't compile.
+
+2006-03-30 07:48  davidm
+
+       * Kconfig, Makefile, talitos/talitos.c, talitos/talitos_dev.h,
+       talitos/talitos_soft.h: 
+       
+       Please find attached the freescale SEC driver for OCF.  It's been
+       (most recently) tested on an SEC2.0 based MPC8541E
+       (cryptographically identical to the MPC8555E) under 2.6.15.2, with
+       openssl-0.9.8a and openswan-2.4.3 (2.4.5rc5 won't keep the security
+       association up for me for some reason).
+       
+       Please feel free to add it to your next release of OCF-Linux :-)
+       
+       Kim Phillips 
+
+2006-03-20 19:34  davidm
+
+       * safe/: safe.c, safevar.h: 
+       
+       Safenet 1141 v1.0 chips have a DMA lockup error if you access the
+       chip while DMA'ing.  As a work around you need to limit your DMA to
+       256 byte chunks using scatter/gather descriptors.  All the SG/SME
+       products have v1.0 chips and would lockup with more than two
+       outstanding packets at one time.
+       
+       Fix the KASSERT macro
+       
+       Add some more exhaustive initialisation.
+
+2006-03-15 21:58  davidm
+
+       * cryptodev.h, random.c: 
+       
+       Switch random support to "ints" since that is what the kernel uses
+       and not using the same thing is 64bit wise a bad idea.
+       
+       Fix FIP's code to ensure correct amount of data is passed in.
+       
+       Add work around for broken 64bit OS RNG support (disable it)
+       
+       General code cleanups.
+
+2006-03-15 21:55  davidm
+
+       * hifn/hifn7751.c: 
+       
+       Fixes for 64bit OS's,  make sure PCI address are within bus space,
+       make sure we order writes to the bus so that chip functions
+       correctly.  Some small cleanups.
+
+2006-03-15 21:48  davidm
+
+       * hifn/hifn7751var.h: 
+       
+       Remove unused field from structure
+
+2006-03-15 21:47  davidm
+
+       * safe/safe.c: 
+       
+       Make the code more 64bit OS compatible,  force PCI address space
+       and so on.
+
+2006-03-09 20:42  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       If we call ixpCryptoAccInit() and it fails,  just assume that it
+       has already been called.  This allows our "rc" scripts to be
+       openswan and freeswan compatible ore easily.
+
+2006-02-28 23:21  davidm
+
+       * README: 
+       
+       generalise it a bit so rel-dates don't get in the way
+
+2006-02-28 01:52  davidm
+
+       * README, patches/ssh.patch, patches/ssl.patch: 
+       
+       Updated the README and patches for a release
+
+2006-02-25 09:21  davidm
+
+       * README, README.sglinux: 
+       
+       updates for a new release of OCF,  ssl patches and so on.
+
+2006-02-25 08:44  davidm
+
+       * crypto.c: 
+       
+       We were calling the "process"routines with interrupts disabled.  I
+       can see no good reason for this and it provokes badness warnings in
+       2.6 under some conditions.
+       
+       I am going to run with the Q's unlocked for processing,  and
+       hopefully it will allow the system to be more responsive.  It
+       hasn't affected ipsec throughput in any way.  Userland throughput
+       (multi threaded) may have improved significantly though,  but it
+       needs more testing.
+
+2006-02-24 23:32  davidm
+
+       * cryptodev.c: 
+       
+       Whoa,  set the segments with uninitted values can't be good.  Clean
+       out the rest of the old code that was accidently left in.
+
+2006-02-22 01:02  davidm
+
+       * cryptodev.c: 
+       
+       Still not sure about this one,  but this is working for all the
+       cases I can see so far.  If it gets weird,  I am going to switch to
+       a simple clone and chain the sessions rather than a new fcr per fd.
+
+2006-02-20 22:12  davidm
+
+       * cryptodev.c: 
+       
+       Error handling case could free data that was not allocated
+       
+       Ronen Shitrit  Marvell Semiconductor Israel
+       Ltd
+
+2006-02-20 21:57  davidm
+
+       * cryptosoft.c: 
+       
+       Proper SHA/MD5 (non hmac) implementation,  remove some retrictions
+       for hashes (which only applied to crypto) and fix over zealous
+       error checking.
+       
+       Ronen Shitrit  Marvell Semiconductor Israel
+       Ltd
+
+2006-02-09 21:15  davidm
+
+       * cryptodev.c: 
+       
+       The code wasn't quite right and needed some fixing for proper file
+       accounting.
+
+2006-01-24 20:08  davidm
+
+       * crypto.c, cryptodev.c, hifn/hifn7751.c: 
+       
+       We implement our own open in the CRIOGET ioctl now which does
+       pretty much the same thing as the BSD version,  rather than use an
+       open system call which gets caught out by chroot.
+
+2006-01-06 00:42  gerg
+
+       * cryptosoft.c: 
+       
+       Moved "{" block marker inside the set of
+       "defined(CONFIG_CRYPTO_HMAC) || defined(CONFIG_CRYPTO_HMAC_MODULE)"
+       code (in function swcr_process) so that it compiled if these where
+       not defined.
+
+2005-11-11 01:44  davidm
+
+       * Makefile, README: 
+       
+       cleanups for a general release of OCF
+
+2005-11-11 01:18  davidm
+
+       * patches/ssl.patch: 
+       
+       Updated the ssl patch to the latest and greatest changed we have
+       made.
+
+2005-11-10 21:41  davidm
+
+       * Makefile, ixp4xx/ixp4xx.c: 
+       
+       Better debug for bad input.
+       
+       Have make clean do more cleaning and less talking.
+
+2005-11-03 20:53  davidm
+
+       * cryptosoft.c: 
+       
+       clean up some compilation errors with various options on/off
+
+2005-10-25 00:25  davidm
+
+       * Makefile: 
+       
+       Add a patch target that generates full kernel patches to add OCF
+       into either a 2.4 or 2.6 kernel as a single patch.
+
+2005-10-25 00:24  davidm
+
+       * Kconfig: 
+       
+       Make sure all OCF settings depend on OCF_OCF
+
+2005-09-23 02:45  davidm
+
+       * README, README.sglinux: 
+       
+       new crypto-tools archive to keep the tools up to date
+
+2005-09-23 02:08  davidm
+
+       * Makefile, README, README.sglinux: 
+       
+       updates for doing OCF releases
+
+2005-09-23 01:59  davidm
+
+       * patches/: ssh.patch, ssl.patch: 
+       
+       updated the patches for the latest in fixes etc to ssh/ssl for a
+       new OCF release before the openswan 2.4.1 merge.
+
+2005-09-21 00:57  davidm
+
+       * Makefile, cryptosoft.c, hifn/hifn7751.c, ixp4xx/ixp4xx.c: 
+       
+       Fixes for building cleanly under 2.6
+
+2005-09-13 23:11  davidm
+
+       * ocf-bench.c: 
+       
+       Add an exit function for cleaner 2.6 support.  Patch from Ronen
+       Shitrit 
+
+2005-07-30 00:23  davidm
+
+       * cryptosoft.c: 
+       
+       Add proper hooks for MD5/SHA and their HMAC countrparts processing
+       from cryptodev.
+
+2005-07-29 01:50  davidm
+
+       * cryptodev.c: 
+       
+       cryptodev did not support MD5 and SHA1,  only the HMAC versions
+
+2005-07-29 01:05  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       register for MD5,  return 16 bytes for MD5 and 12 for MD5_HMAC, 
+       likewise for SHA1 (only 20 is not HMAC).
+
+2005-07-28 21:52  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       First pass fix of userland MD5 processing.  We now do as well as
+       the safenet does,  I think.
+
+2005-07-27 06:23  davidm
+
+       * cryptodev.c: 
+       
+       udelay doesn't give up the current thread, thus the kernel will get
+       locked if a process is killed but the hardware never completes the
+       crypto request.
+
+2005-07-22 02:07  davidm
+
+       * crypto.c, cryptodev.h: 
+       
+       Implement queuing limits for input/output and OCF requests.
+       
+       Implement 2.6 style work queues instead of the 2.4 task_queues.
+
+2005-07-21 20:42  davidm
+
+       * cryptodev.h, ocf-bench.c, ixp4xx/ixp4xx.c: 
+       
+       Fix OCF to use work queues,  add 2.4 version of work queues to
+       cryptodev.h for use in ipsec and elsewhere.
+       
+       Problem and initial patch provided by David Vrabel
+       .  Cleaned up and 2.4 support added by me.
+
+2005-07-21 19:08  davidm
+
+       * random.c: 
+       
+       Fix spinlock initialisation, problem reported by Andy @
+       windsorcarclub.co.uk.
+
+2005-07-20 20:24  davidm
+
+       * cryptodev.c: 
+       
+       fix a silly spelling mistake
+
+2005-07-08 00:56  gerg
+
+       * Makefile: 
+       
+       Only build ocf-bench when CONFIG_OCF_BENCH is acrually enabled.
+
+2005-06-27 20:29  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Ok,  we need a simple implentation here or we go too slow for UDP
+       tests.  For now,  if the Q is full just ditch the packet,  someone
+       has to do it.
+
+2005-06-25 01:13  davidm
+
+       * safe/safe.c: 
+       
+       bytes swapping etc all seems wrong for safenet on BE,  these fixes
+       see both MD5 and SHA1 working with OpenSwan.
+
+2005-06-22 23:10  davidm
+
+       * random.c: 
+       
+       clean up some ifdef code a little
+
+2005-06-22 21:28  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Make sure we do not call blocking functions from ISR callable
+       routines.  In this case we were calling ixCryptoAccCtxUnregister.
+       
+       Run all the random numbers through SHA1 process to ensure more
+       uniform distribution of bits (NOTE:  it is not more random in any
+       way)
+
+2005-06-21 00:11  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       do not process requests from the register callback, gets the AES
+       code all messed up.
+       
+       Align caches on HW cache boundaries ot improve speed.
+       
+       More tracking or potential errors.
+
+2005-06-15 01:55  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       technically ixCryptoAccCtxRegister cannot be called from IRQ
+       context, so run it from the immediate BH.
+
+2005-06-14 23:13  davidm
+
+       * ocf-bench.c: 
+       
+       Fix some compile warnings/errors
+
+2005-06-14 20:52  davidm
+
+       * Config.in, Kconfig, Makefile, ocf-bench.c: 
+       
+       Add in kernel benchmark driver
+       
+       Support for building under CSR 1.4 and 2.0 is now complete
+
+2005-06-14 20:51  davidm
+
+       * crypto.c: 
+       
+       Do not use immediate processing for SW drivers otherwise we hold a
+       lock for too long.  Instead force BATCH processing.
+       
+       Problem found by David Vrabel 
+
+2005-06-14 20:46  davidm
+
+       * cryptodev.c: 
+       
+       Fix up AES minimum key size
+       
+       Make some more variables static
+
+2005-06-14 20:36  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Use kernel caches as they are more efficient and faster to obtain.
+       
+       Fix some spelling
+       
+       Tune PKE to only use the space required.  Turn off go fast options
+       to reduce any speed-related cracking.
+       
+       Only zero data that needs to be zeroed (save some cycles)
+
+2005-06-02 21:42  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Added optimisations ideas from Intel the improve the PKE
+       performance for 512 and 1024 bits operations.
+
+2005-06-01 02:13  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Looks like I found the ixp bug.  Using OSAL buffer routines on
+       non-OSAL buffers is a very very bad thing to do.  Must double check
+       all the API's I am using (ie., PKE) just to be sure.
+
+2005-05-31 21:38  davidm
+
+       * Config.in, Kconfig: 
+       
+       Updated/Added the menu wrapper for the config options
+
+2005-05-31 21:18  gerg
+
+       * Config.in: 
+       
+       Reworked the config.in so that each sub-module has its own
+       Config.in.  That way it is easier to make release trees with some
+       modules left in.
+
+2005-05-30 19:46  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       Not all the Pke code was appropriately ifdef'd
+
+2005-05-28 01:49  davidm
+
+       * cryptosoft.c: 
+       
+       We were not injecting data in the right places nor calling the
+       cipher code the best was under all situations.  We are now good
+       enought to do ESP/AH processing with 3DES and SHA1-HMAC.
+
+2005-05-28 01:42  davidm
+
+       * hifn/hifn7751.c: 
+       
+       Non atomic kmallocs at IRQ time are bad and cause lockups
+
+2005-05-21 08:31  davidm
+
+       * README, README.sglinux: 
+       
+       Some small updates to email and patches that no longer exist
+
+2005-05-21 08:25  davidm
+
+       * cryptosoft.c: 
+       
+       better error message on failure,  a lot of the error check we do
+       sems to break apps like cryptotest, not sure who is right yet.
+
+2005-05-21 00:55  davidm
+
+       * criov.c, crypto.c, cryptodev.c, cryptodev.h, cryptosoft.c,
+       random.c, rndtest.c, uio.h, hifn/hifn7751.c, ixp4xx/ixp4xx.c,
+       safe/safe.c, safe/safevar.h: 
+       
+       Convert to CyberGuard email addresses for OCF files.
+
+2005-05-21 00:28  davidm
+
+       * crypto.c, cryptodev.c, cryptosoft.c, hifn/hifn7751.c,
+       ixp4xx/ixp4xx.c, safe/safe.c: 
+       
+       final round of naming changes,  hifn driver also confirmed working
+       in SG710
+
+2005-05-20 23:50  davidm
+
+       * cryptosoft.c, random.c, uio.h, ixp4xx/ixp4xx.c: 
+       
+       more copyright/author updates etc for Intel
+
+2005-05-20 23:48  davidm
+
+       * criov.c, crypto.c, cryptodev.c, cryptodev.h, cryptosoft.c,
+       random.c, rndtest.c, uio.h, ixp4xx/ixp4xx.c, safe/safe.c,
+       safe/safevar.h: 
+       
+       updated copyrights to reflect Intels interest/investment in the
+       project
+
+2005-05-20 20:31  davidm
+
+       * hifn/: hifn7751.c, hifn7751var.h: 
+       
+       Most of a working SKB implementation now
+
+2005-05-20 20:30  davidm
+
+       * safe/: md5.c, md5.h, safe.c, sha1.c, sha1.h: 
+       
+       Full AH/ESP processing now working,  just added BSD sha/md5
+       routines as needed for now.
+
+2005-05-20 20:30  davidm
+
+       * random.c: 
+       
+       use the new BSD rndtest code rather than the old GPL fips code
+
+2005-05-20 20:28  davidm
+
+       * Makefile, fips.c, fips.h, rndtest.c, rndtest.h: 
+       
+       Get rid of the GPL version of the fips test and use a BSD licensed
+       version so no one can get upset and cry derivative :-)
+
+2005-05-20 08:19  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       High throughput improvements. Can now handle multiple simultaneous
+       requests.
+
+2005-05-20 00:55  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       
+       works with openswan/OCF for ipsec receive.
+       
+       fixes ESP/AUTH processing (esp. HMAC)
+       
+       This driver needs a rework for kernel IPSEC as it's current packet
+       at a time processing is not up to the task.
+
+2005-05-20 00:53  davidm
+
+       * cryptosoft.c: 
+       
+       working ESP/AUTH code now impleneted.  Can do RX processing for
+       openswan KLIPS.
+       
+       Fixes numerous problems in skb processing
+       
+       Fixes broken HMAC code and IV processing
+
+2005-05-14 01:44  davidm
+
+       * cryptodev.c, ixp4xx/ixp4xx.c: 
+       
+       Cleanup IXP key processing to guarantee only a single outstanding
+       request rather than relying on the intel driver to get it right. 
+       Stops us losing requests.
+       
+       Tighten up the cryptodev response to "no answer" so that we don't
+       take all the CPU.  Only happens if there is a driver bug.
+
+2005-05-14 00:07  davidm
+
+       * Config.in, Kconfig, Makefile, crypto.c, fips.c, fips.h, random.c,
+       ixp4xx/ixp4xx.c, tools/bench-ocf: 
+       
+       PKE and RNG support running on the ixp driver,  added PKE bench
+       marking to script.  Still some multi-thread problems in the PKE
+       code.
+       
+       Added FIP RNG checking option to config and code.
+
+2005-05-10 19:18  davidm
+
+       * Makefile, ixp4xx/ixp4xx.c: 
+       
+       Get the OCF stuff building for the 465 and CSR-2.0
+
+2005-04-27 19:18  davidm
+
+       * cryptodev.h, random.c, hifn/hifn7751.c, safe/safe.c: 
+       cleanup the random number interface some more
+
+2005-04-27 00:57  davidm
+
+       * cryptodev.h, cryptosoft.c, random.c, hifn/hifn7751.c,
+       ixp4xx/ixp4xx.c, patches/linux-2.4.29-add_true_randomness.patch,
+       patches/linux-2.6.11-add_true_randomness.patch, safe/safe.c,
+       safe/safevar.h: 
+       
+       Switch to a more "user" like random number handling.  Drivers no
+       longer poll for RNG data,  we pull it as needed to fill
+       /dev/random's entropy.
+       
+       Implement sk_buff handling within the OCF framework.
+       
+       fixup IV handling in cryptosoft.
+
+2005-04-27 00:41  davidm
+
+       * crypto.c: 
+       
+       Fix a race condition with the starting of kernel threads.  The
+       threads were running before the pid assignment in the parent.
+
+2005-03-24 23:57  davidm
+
+       * Makefile: 
+       include crypto-tools.patch in the release file
+       
+       
+
+2005-03-24 20:14  davidm
+
+       * safe/safe.c: 
+       Fixup compile time warnings due to some left over BSDisms
+       
+
+2005-03-24 00:53  davidm
+
+       * Makefile, README, README.sglinux, patches/linux-2.4.29-ocf.patch,
+       patches/linux-2.6.11-ocf.patch, patches/ocf-linux-2.4.29.patch,
+       patches/ocf-linux-2.6.11.patch: 
+       added cleaner patch names and a tarball target to aid releases
+       
+
+2005-03-24 00:28  davidm
+
+       * patches/crypto-tools.patch,
+       patches/linux-2.4.29-add_true_randomness.patch,
+       patches/linux-2.6.11-add_true_randomness.patch,
+       patches/ocf-linux-2.4.29.patch, patches/ocf-linux-2.6.11.patch,
+       patches/ssh.patch, patches/ssl.patch, tools/bench-ocf: 
+       move all the release file patches into CVS for simplicity
+       
+
+2005-03-23 20:37  davidm
+
+       * safe/safe.c: 
+       remove excessive debug from RNG routines so that you can turn on
+       debug and live through it
+       
+       
+
+2005-03-23 02:23  davidm
+
+       * safe/safe.c: 
+       fix memory corruption for mod_exp and the safenet,  we were copying
+       back more than the space available.
+       
+       
+
+2005-03-22 21:45  davidm
+
+       * crypto.c, cryptodev.c, cryptodev.h, safe/safe.c: 
+       fixup a major sync issues with key processing (callback called
+       before sleeping).  Improve its performance while we are there with
+       a CBIMM (callback immediate) option.
+       
+       
+
+2005-03-19 00:33  davidm
+
+       * random.c: 
+       A new randomness function for both 2.4 and 2.6 that replaces out
+       previous old solution for the hifn driver with more generic code
+       that works on both kernels.
+       
+               add_true_randomness(u_int32_t *buf, int nwords);
+       
+       
+
+2005-03-18 21:01  davidm
+
+       * Makefile, cryptodev.h, random.c, hifn/hifn7751.c, safe/safe.c: 
+       RNG support in both the safenet and the hifn plus the required
+       kernel support.
+       
+       "hd /dev/random" runs much much faster now :-)
+       
+       
+
+2005-03-17 23:29  toby
+
+       * cryptodev.c:  Make sure the CIOCASYMFEAT ioctl on
+       /dev/crypto copies out the capable features.
+
+2005-03-17 01:19  davidm
+
+       * safe/: safe.c, safereg.h, safevar.h: 
+       hardware PK acceleration on the safenet (CRK_MOD_EXP only)
+       
+
+2005-03-16 04:28  davidm
+
+       * criov.c, crypto.c, cryptodev.c, safe/safe.c: 
+       fixup the FBSD id stuff to compile :-) 
+
+2005-03-16 04:02  davidm
+
+       * README, README.sglinux, TODO: 
+       Updated with versions,  removed tabs,  new kernel versions, web
+       site etc 
+
+2005-03-16 03:45  davidm
+
+       * criov.c, crypto.c, cryptodev.c, cryptodev.h: 
+       more license formatting and version id's to help keep in touch with
+       FreeBSD 
+
+2005-03-16 03:16  davidm
+
+       * safe/safe.c: 
+       up to date with FreeBSD versioning, no changes to merge 
+
+2005-03-16 03:15  davidm
+
+       * safe/safe.c: 
+       include FreeBSD version info so I can track changes better
+       
+
+2005-03-16 03:11  davidm
+
+       * hifn/: hifn7751.c, hifn7751reg.h, hifn7751var.h: 
+       incorporate latest updates from FreeBSD:
+       
+       | Update support for 795x parts: | o rework pll setup code to
+       follow h/w specification | o add hint.hifn.X.pllconfig to specify
+       reference clock setup |   requirements; default is pci66 which
+       means the clock is |   derived from the PCI bus clock and the card
+       resides in a |   66MHz slot | | Tested on 7955 and 7956 cards;
+       support for 7954 cards not enabled | since we have no cards to test
+       against.
+       
+       
+
+2005-03-16 02:50  davidm
+
+       * Config.in, Kconfig, README, crypto.c, cryptodev.c, cryptodev.h,
+       hifn/hifn7751.c, hifn/hifn7751var.h, safe/safe.c, safe/safevar.h: 
+       cleanups to build and run on 2.6.11 and 2.4.29 for a public release
+       
+       included configs locally to reduce patch to kernel and required
+       user effort.
+       
+       pci_dma_sync_single fix from Michele Baldessari
+       ,       with modifications by me to work on all
+       kernels.
+       
+       
+
+2005-03-11 23:30  davidm
+
+       * Makefile: 
+       fix up the compiling again, I had outstanding commits for this one
+       :-) 
+
+2005-03-11 21:56  danield
+
+       * Makefile: Get ocf modules building again.  
+
+2004-12-25 07:12  davidm
+
+       * TODO: 
+       safenet is all good now AKAIK 
+
+2004-12-25 07:02  davidm
+
+       * Makefile, crypto.c, cryptodev.c, cryptosoft.c, uio.h: 
+       2.6 port of the OCF framework,  tested on Xscale and compiled for
+       x86
+       
+       
+
+2004-12-10 02:41  davidm
+
+       * hifn/hifn7751.c: 
+       Fix compilation as l_flags was not defined for LOCK in pci_remove
+       
+
+2004-12-06 19:15  davidm
+
+       * hifn/hifn7751.c, safe/safe.c: 
+       * Put locking into hifn_remove to ensure interrupts are not running
+       while we   remove the driver
+       
+         Use del_timer_sync (need to ensure timer is not running on
+       another CPU
+       * when we delete it).
+       
+       Improvements suggested by Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+       
+
+2004-12-02 09:16  davidm
+
+       * README, README.sglinux: 
+       * Fix up all tabs to be spaces * explain how to update the ocf
+       support in the patch to the current version.
+       
+       
+
+2004-12-02 09:11  davidm
+
+       * README: 
+       * fix some spelling/grammar * add more info on the ssl.patch file
+       and what it contains 
+
+2004-12-02 09:08  davidm
+
+       * README.sglinux: 
+       give some more instructions on the shar archive and extracting the
+       release.  
+
+2004-12-02 09:03  davidm
+
+       * README.sglinux: 
+       how to include crypto-tools into 3.1.6
+       
+       
+
+2004-12-02 08:48  davidm
+
+       * README.sglinux: 
+       updated for a new crypto patch for openssl-0.9.7e 
+
+2004-12-02 08:04  davidm
+
+       * README, README.sglinux: 
+       Clean up the README's to use the new SG Linux alpha and a specific
+       2.4.28 patch.
+       
+       
+
+2004-12-01 23:11  davidm
+
+       * Makefile, criov.c, crypto.c, cryptodev.c, cryptosoft.c,
+       hifn/Makefile, hifn/hifn7751.c, ixp4xx/Makefile, ixp4xx/ixp4xx.c,
+       safe/Makefile, safe/safe.c: 
+       Re-worked the Makefiles so that including the code into a standard
+       non-SG kernel is really easy.
+       
+       Fixed a non-initialised bug that was introduce into cryptosoft.c
+       with the additional error checking.
+       
+       
+
+2004-12-01 01:54  davidm
+
+       * TODO: 
+       updates based on things that have been fixed.  
+
+2004-12-01 01:53  davidm
+
+       * safe/: safe.c, safevar.h: 
+       Cleanup some old hacks based on the much cleaner port of the hifn
+       driver.  
+
+2004-12-01 01:53  davidm
+
+       * cryptosoft.c: 
+       fix some crashes due to bad buffer sizes etc.  
+
+2004-11-27 09:16  davidm
+
+       * crypto.c, cryptodev.c, ixp4xx/ixp4xx.c: 
+       Fixed some nasty problems that were stopping reliable behaviour:
+       
+       1) we were not initialising some of our lists/wait queues,  which  
+        meant they appears to have things in them when in fact they did
+       not.     This actually didn't seems to cause any problems but is
+       extremely bogus.
+       
+       2) While a process was waiting for the crypto engine,  if
+       itreceived a    signal we would lose sync with the engine and end
+       up allowing out-of-band    actions that were invalid (ie.,
+       unregistering a context that was still    active in a crypto
+       operation).
+       
+          Of source the CryptACC should probably deal with this as well
+       ;-)
+       
+       
+
+2004-11-26 01:33  davidm
+
+       * TODO: 
+       We should also hook in the random number generators to linux
+       
+
+2004-11-26 01:33  davidm
+
+       * hifn/hifn7751.c: 
+       Changed all the accesses to DMS descriptors to not set the valid
+       bit until after everything else was set.  This got the driver
+       running smoothly, along with a fixup to the pci_map_uio which
+       wasn't settings lengths correctly.
+       
+       
+
+2004-11-25 21:15  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       document why using a new context for each packet is actually a
+       better idea than allocating one (actually two) per session.
+       
+       
+
+2004-11-25 08:48  davidm
+
+       * README, README.sglinux: 
+       updates from email with Intel to fix a few little things
+       
+
+2004-11-25 00:02  davidm
+
+       * README, README.sglinux, safe/safe.c: 
+       Some cleanups of doc and so on for Intel/General use 
+
+2004-11-23 07:58  davidm
+
+       * TODO: 
+       safenet is working on big endian machines now
+       
+       
+
+2004-11-23 07:56  davidm
+
+       * ixp4xx/: Makefile, ixp4xx.c: 
+       Reference the Intel library,  cleanup the IV sizes and turn on AES.
+        Fix Makefile for new config options.
+       
+       
+
+2004-11-23 07:52  davidm
+
+       * Makefile: 
+       Complete the changes of ixp to ixp4xx (IXP4xx) as appropriate
+       
+
+2004-11-23 00:33  davidm
+
+       * Makefile, README, ixp4xx/Makefile: 
+       Changes all references to ixp to be ixp4xx at Intels request
+       
+
+2004-11-20 01:07  davidm
+
+       * safe/: safe.c, safereg.h: 
+       fully working safenet on BE machines 
+
+2004-11-19 01:03  davidm
+
+       * Makefile, hifn/Makefile, hifn/hifn7751.c, hifn/hifn7751reg.h,
+       hifn/hifn7751var.h: 
+       hifn driver code complete and compiling,  needs a test now ;-)
+       
+
+2004-11-18 21:45  davidm
+
+       * hifn/: Makefile, hifn7751.c, hifn7751var.h: 
+       Makefile for building the hifn driver 
+
+2004-11-18 21:44  davidm
+
+       * hifn/: hifn7751.c, hifn7751reg.h, hifn7751var.h: 
+       Checkin the orginal freebsd source for the hifn driver as a
+       reference in the future.
+       
+       
+
+2004-11-18 10:05  davidm
+
+       * Makefile, README, TODO, criov.c, crypto.c, cryptodev.c,
+       cryptodev.h, cryptosoft.c, uio.h, ixp4xx/Makefile, ixp4xx/ixp4xx.c,
+       safe/Makefile, safe/safe.c, safe/safevar.h: 
+       Clean up license and copyright info to be more acceptable (and
+       present) Clean up debug and trace Fixup memory freeing etc on
+       safenet Fix compiler warnings (some were bugs)
+       
+       
+
+2004-11-17 02:23  davidm
+
+       * safe/safe.c: 
+       working on Xscale (big endian) now but packet data is getting
+       stuffed up due to endian problems (at least now we are talking to
+       the chip correctly for BE).  Good enough to test packet throughput,
+        no good for testing scp.
+       
+       
+
+2004-11-17 02:21  davidm
+
+       * criov.c: 
+       Make sure public symbols are exported by including the correct
+       header files 
+
+2004-11-17 02:15  davidm
+
+       * crypto.c: 
+       even better cleanup of kernel threads on exit 
+
+2004-11-17 02:15  davidm
+
+       * cryptosoft.c: 
+       return some trace to debug so it doesn't appear 
+
+2004-11-17 02:14  davidm
+
+       * Makefile: 
+       Make sure all drivers get built, not just IXP 
+
+2004-11-16 21:31  davidm
+
+       * crypto.c: 
+       Fix problem with reboots and driver not unloading cleanly,  we were
+       not handling signals correctly in the kernel threads, 
+
+2004-11-10 10:46  davidm
+
+       * ixp4xx/ixp4xx.c: 
+       fix serious context leak,  itturns out the context is still
+       considered busy while it is calling the perform callback,  so we
+       cleanup on closing the session and on allocating the next context
+       to work around this.
+       
+       
+
+2004-11-10 05:26  davidm
+
+       * crypto.c, cryptodev.c, ixp4xx/ixp4xx.c, safe/safe.c: 
+       cleaned out some debug,  found MAX tunnels bug,  traced it various
+       other cleanups.
+       
+       
+
+2004-11-10 04:02  davidm
+
+       * cryptodev.c, cryptosoft.c, ixp4xx/ixp4xx.c, safe/Makefile,
+       safe/safe.c: 
+       Fix up kmalloc usage to always zero resulting buffer everywhere   
+       (stops crashes in ixp)
+       
+       Add some function debug to ixp so you can see it working
+       
+       Fix safe driver to build and install in a real tree.
+       
+       
+
+2004-11-10 02:27  davidm
+
+       * Makefile, criov.c, crypto.c, cryptosoft.c, ixp4xx/Makefile,
+       ixp4xx/ixp4xx.c: 
+       Compiling OCF modules for the IXP crypto, needs testing now
+       
+
+2004-11-09 19:16  davidm
+
+       * criov.c, crypto.c, cryptodev.c, cryptodev.h, cryptosoft.c,
+       cryptosoft.h, uio.h, safe/safe.c, safe/safevar.h: 
+       The linux port of OCF with working safenet and software modules. 
+       Still some bugs with mutiple crypto threads using the safenet
+       driver.
+       
+       
+
+2004-11-09 18:49  davidm
+
+       * Makefile, criov.c, crypto.c, cryptodev.c, cryptodev.h,
+       cryptosoft.c, cryptosoft.h, uio.h, safe/Makefile, safe/safe.c,
+       safe/safereg.h, safe/safevar.h: 
+       Check in the orginal free-bsd sources for the OCF support.  This
+       allows us to diff against it later to see if we botched anything
+       major league.
+       
+       
+
diff --git a/target/linux/generic-2.6/files/crypto/ocf/Config.in b/target/linux/generic-2.6/files/crypto/ocf/Config.in
new file mode 100644 (file)
index 0000000..cb01ea9
--- /dev/null
@@ -0,0 +1,34 @@
+#############################################################################
+
+mainmenu_option next_comment
+comment 'OCF Configuration'
+tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF
+dep_mbool '  enable fips RNG checks (fips check on RNG data before use)' \
+                               CONFIG_OCF_FIPS $CONFIG_OCF_OCF
+dep_mbool '  enable harvesting entropy for /dev/random' \
+                               CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF
+dep_tristate '  cryptodev (user space support)' \
+                               CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF
+dep_tristate '  cryptosoft (software crypto engine)' \
+                               CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF
+dep_tristate '  safenet (HW crypto engine)' \
+                               CONFIG_OCF_SAFE $CONFIG_OCF_OCF
+dep_tristate '  IXP4xx (HW crypto engine)' \
+                               CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF
+dep_mbool    '  Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \
+                               CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX
+dep_tristate '  hifn (HW crypto engine)' \
+                               CONFIG_OCF_HIFN $CONFIG_OCF_OCF
+dep_tristate '  talitos (HW crypto engine)' \
+                               CONFIG_OCF_TALITOS $CONFIG_OCF_OCF
+dep_tristate '  pasemi (HW crypto engine)' \
+                               CONFIG_OCF_PASEMI $CONFIG_OCF_OCF
+dep_tristate '  ep80579 (HW crypto engine)' \
+                               CONFIG_OCF_EP80579 $CONFIG_OCF_OCF
+dep_tristate '  ocfnull (does no crypto)' \
+                               CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF
+dep_tristate '  ocf-bench (HW crypto in-kernel benchmark)' \
+                               CONFIG_OCF_BENCH $CONFIG_OCF_OCF
+endmenu
+
+#############################################################################
diff --git a/target/linux/generic-2.6/files/crypto/ocf/Kconfig b/target/linux/generic-2.6/files/crypto/ocf/Kconfig
new file mode 100644 (file)
index 0000000..74b98b2
--- /dev/null
@@ -0,0 +1,101 @@
+menu "OCF Configuration"
+
+config OCF_OCF
+       tristate "OCF (Open Cryptograhic Framework)"
+       help
+         A linux port of the OpenBSD/FreeBSD crypto framework.
+
+config OCF_RANDOMHARVEST
+       bool "crypto random --- harvest entropy for /dev/random"
+       depends on OCF_OCF
+       help
+         Includes code to harvest random numbers from devices that support it.
+
+config OCF_FIPS
+       bool "enable fips RNG checks"
+       depends on OCF_OCF && OCF_RANDOMHARVEST
+       help
+         Run all RNG provided data through a fips check before
+         adding it /dev/random's entropy pool.
+
+config OCF_CRYPTODEV
+       tristate "cryptodev (user space support)"
+       depends on OCF_OCF
+       help
+         The user space API to access crypto hardware.
+
+config OCF_CRYPTOSOFT
+       tristate "cryptosoft (software crypto engine)"
+       depends on OCF_OCF
+       help
+         A software driver for the OCF framework that uses
+         the kernel CryptoAPI.
+
+config OCF_SAFE
+       tristate "safenet (HW crypto engine)"
+       depends on OCF_OCF
+       help
+         A driver for a number of the safenet Excel crypto accelerators.
+         Currently tested and working on the 1141 and 1741.
+
+config OCF_IXP4XX
+       tristate "IXP4xx (HW crypto engine)"
+       depends on OCF_OCF
+       help
+         XScale IXP4xx crypto accelerator driver.  Requires the
+         Intel Access library.
+
+config OCF_IXP4XX_SHA1_MD5
+       bool "IXP4xx SHA1 and MD5 Hashing"
+       depends on OCF_IXP4XX
+       help
+         Allows the IXP4xx crypto accelerator to perform SHA1 and MD5 hashing.
+         Note: this is MUCH slower than using cryptosoft (software crypto engine).
+
+config OCF_HIFN
+       tristate "hifn (HW crypto engine)"
+       depends on OCF_OCF
+       help
+         OCF driver for various HIFN based crypto accelerators.
+         (7951, 7955, 7956, 7751, 7811)
+
+config OCF_HIFNHIPP
+       tristate "Hifn HIPP (HW packet crypto engine)"
+       depends on OCF_OCF
+       help
+         OCF driver for various HIFN (HIPP) based crypto accelerators
+         (7855)
+
+config OCF_TALITOS
+       tristate "talitos (HW crypto engine)"
+       depends on OCF_OCF
+       help
+         OCF driver for Freescale's security engine (SEC/talitos).
+
+config OCF_PASEMI
+       tristate "pasemi (HW crypto engine)"
+       depends on OCF_OCF && PPC_PASEMI
+       help
+         OCF driver for the PA Semi PWRficient DMA Engine
+
+config OCF_EP80579
+       tristate "ep80579 (HW crypto engine)"
+       depends on OCF_OCF
+       help
+         OCF driver for the Intel EP80579 Integrated Processor Product Line.
+
+config OCF_OCFNULL
+       tristate "ocfnull (fake crypto engine)"
+       depends on OCF_OCF
+       help
+         OCF driver for measuring ipsec overheads (does no crypto)
+
+config OCF_BENCH
+       tristate "ocf-bench (HW crypto in-kernel benchmark)"
+       depends on OCF_OCF
+       help
+         A very simple encryption test for the in-kernel interface
+         of OCF.  Also includes code to benchmark the IXP Access library
+         for comparison.
+
+endmenu
diff --git a/target/linux/generic-2.6/files/crypto/ocf/Makefile b/target/linux/generic-2.6/files/crypto/ocf/Makefile
new file mode 100644 (file)
index 0000000..919e551
--- /dev/null
@@ -0,0 +1,121 @@
+# for SGlinux builds
+-include $(ROOTDIR)/modules/.config
+
+OCF_OBJS = crypto.o criov.o
+
+ifdef CONFIG_OCF_RANDOMHARVEST
+       OCF_OBJS += random.o
+endif
+
+ifdef CONFIG_OCF_FIPS
+       OCF_OBJS += rndtest.o
+endif
+
+# Add in autoconf.h to get #defines for CONFIG_xxx
+AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h
+ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H)))
+       EXTRA_CFLAGS += -include $(AUTOCONF_H)
+       export EXTRA_CFLAGS
+endif
+
+ifndef obj
+       obj ?= .
+       _obj = subdir
+       mod-subdirs := safe hifn ixp4xx talitos ocfnull
+       export-objs += crypto.o criov.o random.o
+       list-multi += ocf.o
+       _slash :=
+else
+       _obj = obj
+       _slash := /
+endif
+
+EXTRA_CFLAGS += -I$(obj)/.
+
+obj-$(CONFIG_OCF_OCF)         += ocf.o
+obj-$(CONFIG_OCF_CRYPTODEV)   += cryptodev.o
+obj-$(CONFIG_OCF_CRYPTOSOFT)  += cryptosoft.o
+obj-$(CONFIG_OCF_BENCH)       += ocf-bench.o
+
+$(_obj)-$(CONFIG_OCF_SAFE)    += safe$(_slash)
+$(_obj)-$(CONFIG_OCF_HIFN)    += hifn$(_slash)
+$(_obj)-$(CONFIG_OCF_IXP4XX)  += ixp4xx$(_slash)
+$(_obj)-$(CONFIG_OCF_TALITOS) += talitos$(_slash)
+$(_obj)-$(CONFIG_OCF_PASEMI)  += pasemi$(_slash)
+$(_obj)-$(CONFIG_OCF_EP80579) += ep80579$(_slash)
+$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash)
+
+ocf-objs := $(OCF_OBJS)
+
+$(list-multi) dummy1: $(ocf-objs)
+       $(LD) -r -o $@ $(ocf-objs)
+
+.PHONY:
+clean:
+       rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c
+       rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags
+
+ifdef TOPDIR
+-include $(TOPDIR)/Rules.make
+endif
+
+#
+# release gen targets
+#
+
+.PHONY: patch
+patch:
+       REL=`date +%Y%m%d`; \
+               patch=ocf-linux-$$REL.patch; \
+               patch24=ocf-linux-24-$$REL.patch; \
+               patch26=ocf-linux-26-$$REL.patch; \
+               ( \
+                       find . -name Makefile; \
+                       find . -name Config.in; \
+                       find . -name Kconfig; \
+                       find . -name README; \
+                       find . -name '*.[ch]' | grep -v '.mod.c'; \
+               ) | while read t; do \
+                       diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \
+               done > $$patch; \
+               cat patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \
+               cat patches/linux-2.6.26-ocf.patch $$patch > $$patch26
+
+.PHONY: tarball
+tarball:
+       REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \
+               CURDIR=`pwd`; \
+               rm -rf /tmp/ocf-linux-$$REL*; \
+               mkdir -p $$RELDIR/tools; \
+               cp README* $$RELDIR; \
+               cp patches/openss*.patch $$RELDIR; \
+               cp patches/crypto-tools.patch $$RELDIR; \
+               cp tools/[!C]* $$RELDIR/tools; \
+               cd ..; \
+               tar cvf $$RELDIR/ocf-linux.tar \
+                                       --exclude=CVS \
+                                       --exclude=.* \
+                                       --exclude=*.o \
+                                       --exclude=*.ko \
+                                       --exclude=*.mod.* \
+                                       --exclude=README* \
+                                       --exclude=ocf-*.patch \
+                                       --exclude=ocf/patches/openss*.patch \
+                                       --exclude=ocf/patches/crypto-tools.patch \
+                                       --exclude=ocf/tools \
+                                       ocf; \
+               gzip -9 $$RELDIR/ocf-linux.tar; \
+               cd /tmp; \
+               tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \
+               gzip -9 ocf-linux-$$REL.tar; \
+               cd $$CURDIR/../../user; \
+               rm -rf /tmp/crypto-tools-$$REL*; \
+               tar cvf /tmp/crypto-tools-$$REL.tar \
+                                       --exclude=CVS \
+                                       --exclude=.* \
+                                       --exclude=*.o \
+                                       --exclude=cryptotest \
+                                       --exclude=cryptokeytest \
+                                       crypto-tools; \
+               gzip -9 /tmp/crypto-tools-$$REL.tar
+
diff --git a/target/linux/generic-2.6/files/crypto/ocf/criov.c b/target/linux/generic-2.6/files/crypto/ocf/criov.c
new file mode 100644 (file)
index 0000000..3bf7c32
--- /dev/null
@@ -0,0 +1,215 @@
+/*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $        */
+
+/*
+ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2006-2007 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Copyright (c) 1999 Theo de Raadt
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $");
+ */
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+
+#include <uio.h>
+#include <cryptodev.h>
+
+/*
+ * This macro is only for avoiding code duplication, as we need to skip
+ * given number of bytes in the same way in three functions below.
+ */
+#define        CUIO_SKIP()     do {                                            \
+       KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));           \
+       KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));           \
+       while (off > 0) {                                               \
+               KASSERT(iol >= 0, ("%s: empty in skip", __func__));     \
+               if (off < iov->iov_len)                                 \
+                       break;                                          \
+               off -= iov->iov_len;                                    \
+               iol--;                                                  \
+               iov++;                                                  \
+       }                                                               \
+} while (0)
+
+void
+cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
+{
+       struct iovec *iov = uio->uio_iov;
+       int iol = uio->uio_iovcnt;
+       unsigned count;
+
+       CUIO_SKIP();
+       while (len > 0) {
+               KASSERT(iol >= 0, ("%s: empty", __func__));
+               count = min((int)(iov->iov_len - off), len);
+               memcpy(cp, ((caddr_t)iov->iov_base) + off, count);
+               len -= count;
+               cp += count;
+               off = 0;
+               iol--;
+               iov++;
+       }
+}
+
+void
+cuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
+{
+       struct iovec *iov = uio->uio_iov;
+       int iol = uio->uio_iovcnt;
+       unsigned count;
+
+       CUIO_SKIP();
+       while (len > 0) {
+               KASSERT(iol >= 0, ("%s: empty", __func__));
+               count = min((int)(iov->iov_len - off), len);
+               memcpy(((caddr_t)iov->iov_base) + off, cp, count);
+               len -= count;
+               cp += count;
+               off = 0;
+               iol--;
+               iov++;
+       }
+}
+
+/*
+ * Return a pointer to iov/offset of location in iovec list.
+ */
+struct iovec *
+cuio_getptr(struct uio *uio, int loc, int *off)
+{
+       struct iovec *iov = uio->uio_iov;
+       int iol = uio->uio_iovcnt;
+
+       while (loc >= 0) {
+               /* Normal end of search */
+               if (loc < iov->iov_len) {
+                       *off = loc;
+                       return (iov);
+               }
+
+               loc -= iov->iov_len;
+               if (iol == 0) {
+                       if (loc == 0) {
+                               /* Point at the end of valid data */
+                               *off = iov->iov_len;
+                               return (iov);
+                       } else
+                               return (NULL);
+               } else {
+                       iov++, iol--;
+               }
+       }
+
+       return (NULL);
+}
+
+EXPORT_SYMBOL(cuio_copyback);
+EXPORT_SYMBOL(cuio_copydata);
+EXPORT_SYMBOL(cuio_getptr);
+
+
+static void
+skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len)
+{
+       int i;
+       if (offset < skb_headlen(skb)) {
+               memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len));
+               len -= skb_headlen(skb);
+               cp += skb_headlen(skb);
+       }
+       offset -= skb_headlen(skb);
+       for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) {
+               if (offset < skb_shinfo(skb)->frags[i].size) {
+                       memcpy(page_address(skb_shinfo(skb)->frags[i].page) +
+                                       skb_shinfo(skb)->frags[i].page_offset,
+                                       cp, min_t(int, skb_shinfo(skb)->frags[i].size, len));
+                       len -= skb_shinfo(skb)->frags[i].size;
+                       cp += skb_shinfo(skb)->frags[i].size;
+               }
+               offset -= skb_shinfo(skb)->frags[i].size;
+       }
+}
+
+void
+crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
+{
+
+       if ((flags & CRYPTO_F_SKBUF) != 0)
+               skb_copy_bits_back((struct sk_buff *)buf, off, in, size);
+       else if ((flags & CRYPTO_F_IOV) != 0)
+               cuio_copyback((struct uio *)buf, off, size, in);
+       else
+               bcopy(in, buf + off, size);
+}
+
+void
+crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
+{
+
+       if ((flags & CRYPTO_F_SKBUF) != 0)
+               skb_copy_bits((struct sk_buff *)buf, off, out, size);
+       else if ((flags & CRYPTO_F_IOV) != 0)
+               cuio_copydata((struct uio *)buf, off, size, out);
+       else
+               bcopy(buf + off, out, size);
+}
+
+int
+crypto_apply(int flags, caddr_t buf, int off, int len,
+    int (*f)(void *, void *, u_int), void *arg)
+{
+#if 0
+       int error;
+
+       if ((flags & CRYPTO_F_SKBUF) != 0)
+               error = XXXXXX((struct mbuf *)buf, off, len, f, arg);
+       else if ((flags & CRYPTO_F_IOV) != 0)
+               error = cuio_apply((struct uio *)buf, off, len, f, arg);
+       else
+               error = (*f)(arg, buf + off, len);
+       return (error);
+#else
+       KASSERT(0, ("crypto_apply not implemented!\n"));
+#endif
+       return 0;
+}
+
+EXPORT_SYMBOL(crypto_copyback);
+EXPORT_SYMBOL(crypto_copydata);
+EXPORT_SYMBOL(crypto_apply);
+
diff --git a/target/linux/generic-2.6/files/crypto/ocf/crypto.c b/target/linux/generic-2.6/files/crypto/ocf/crypto.c
new file mode 100644 (file)
index 0000000..5121b3d
--- /dev/null
@@ -0,0 +1,1741 @@
+/*-
+ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2006-2007 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * Copyright (c) 2002-2006 Sam Leffler.  All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#if 0
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $");
+#endif
+
+/*
+ * Cryptographic Subsystem.
+ *
+ * This code is derived from the Openbsd Cryptographic Framework (OCF)
+ * that has the copyright shown below.  Very little of the original
+ * code remains.
+ */
+/*-
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000, 2001 Angelos D. Keromytis
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $");
+ */
+
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/version.h>
+#include <cryptodev.h>
+
+/*
+ * keep track of whether or not we have been initialised, a big
+ * issue if we are linked into the kernel and a driver gets started before
+ * us
+ */
+static int crypto_initted = 0;
+
+/*
+ * Crypto drivers register themselves by allocating a slot in the
+ * crypto_drivers table with crypto_get_driverid() and then registering
+ * each algorithm they support with crypto_register() and crypto_kregister().
+ */
+
+/*
+ * lock on driver table
+ * we track its state as spin_is_locked does not do anything on non-SMP boxes
+ */
+static spinlock_t      crypto_drivers_lock;
+static int                     crypto_drivers_locked;          /* for non-SMP boxes */
+
+#define        CRYPTO_DRIVER_LOCK() \
+                       ({ \
+                               spin_lock_irqsave(&crypto_drivers_lock, d_flags); \
+                               crypto_drivers_locked = 1; \
+                               dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \
+                        })
+#define        CRYPTO_DRIVER_UNLOCK() \
+                       ({ \
+                               dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \
+                               crypto_drivers_locked = 0; \
+                               spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \
+                        })
+#define        CRYPTO_DRIVER_ASSERT() \
+                       ({ \
+                               if (!crypto_drivers_locked) { \
+                                       dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \
+                               } \
+                        })
+
+/*
+ * Crypto device/driver capabilities structure.
+ *
+ * Synchronization:
+ * (d) - protected by CRYPTO_DRIVER_LOCK()
+ * (q) - protected by CRYPTO_Q_LOCK()
+ * Not tagged fields are read-only.
+ */
+struct cryptocap {
+       device_t        cc_dev;                 /* (d) device/driver */
+       u_int32_t       cc_sessions;            /* (d) # of sessions */
+       u_int32_t       cc_koperations;         /* (d) # os asym operations */
+       /*
+        * Largest possible operator length (in bits) for each type of
+        * encryption algorithm. XXX not used
+        */
+       u_int16_t       cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1];
+       u_int8_t        cc_alg[CRYPTO_ALGORITHM_MAX + 1];
+       u_int8_t        cc_kalg[CRK_ALGORITHM_MAX + 1];
+
+       int             cc_flags;               /* (d) flags */
+#define CRYPTOCAP_F_CLEANUP    0x80000000      /* needs resource cleanup */
+       int             cc_qblocked;            /* (q) symmetric q blocked */
+       int             cc_kqblocked;           /* (q) asymmetric q blocked */
+};
+static struct cryptocap *crypto_drivers = NULL;
+static int crypto_drivers_num = 0;
+
+/*
+ * There are two queues for crypto requests; one for symmetric (e.g.
+ * cipher) operations and one for asymmetric (e.g. MOD)operations.
+ * A single mutex is used to lock access to both queues.  We could
+ * have one per-queue but having one simplifies handling of block/unblock
+ * operations.
+ */
+static int crp_sleep = 0;
+static LIST_HEAD(crp_q);               /* request queues */
+static LIST_HEAD(crp_kq);
+
+static spinlock_t crypto_q_lock;
+
+int crypto_all_qblocked = 0;  /* protect with Q_LOCK */
+module_param(crypto_all_qblocked, int, 0444);
+MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked");
+
+int crypto_all_kqblocked = 0; /* protect with Q_LOCK */
+module_param(crypto_all_kqblocked, int, 0444);
+MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked");
+
+#define        CRYPTO_Q_LOCK() \
+                       ({ \
+                               spin_lock_irqsave(&crypto_q_lock, q_flags); \
+                               dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \
+                        })
+#define        CRYPTO_Q_UNLOCK() \
+                       ({ \
+                               dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \
+                               spin_unlock_irqrestore(&crypto_q_lock, q_flags); \
+                        })
+
+/*
+ * There are two queues for processing completed crypto requests; one
+ * for the symmetric and one for the asymmetric ops.  We only need one
+ * but have two to avoid type futzing (cryptop vs. cryptkop).  A single
+ * mutex is used to lock access to both queues.  Note that this lock
+ * must be separate from the lock on request queues to insure driver
+ * callbacks don't generate lock order reversals.
+ */
+static LIST_HEAD(crp_ret_q);           /* callback queues */
+static LIST_HEAD(crp_ret_kq);
+
+static spinlock_t crypto_ret_q_lock;
+#define        CRYPTO_RETQ_LOCK() \
+                       ({ \
+                               spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \
+                               dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \
+                        })
+#define        CRYPTO_RETQ_UNLOCK() \
+                       ({ \
+                               dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \
+                               spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \
+                        })
+#define        CRYPTO_RETQ_EMPTY()     (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq))
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static kmem_cache_t *cryptop_zone;
+static kmem_cache_t *cryptodesc_zone;
+#else
+static struct kmem_cache *cryptop_zone;
+static struct kmem_cache *cryptodesc_zone;
+#endif
+
+#define debug crypto_debug
+int crypto_debug = 0;
+module_param(crypto_debug, int, 0644);
+MODULE_PARM_DESC(crypto_debug, "Enable debug");
+EXPORT_SYMBOL(crypto_debug);
+
+/*
+ * Maximum number of outstanding crypto requests before we start
+ * failing requests.  We need this to prevent DOS when too many
+ * requests are arriving for us to keep up.  Otherwise we will
+ * run the system out of memory.  Since crypto is slow,  we are
+ * usually the bottleneck that needs to say, enough is enough.
+ *
+ * We cannot print errors when this condition occurs,  we are already too
+ * slow,  printing anything will just kill us
+ */
+
+static int crypto_q_cnt = 0;
+module_param(crypto_q_cnt, int, 0444);
+MODULE_PARM_DESC(crypto_q_cnt,
+               "Current number of outstanding crypto requests");
+
+static int crypto_q_max = 1000;
+module_param(crypto_q_max, int, 0644);
+MODULE_PARM_DESC(crypto_q_max,
+               "Maximum number of outstanding crypto requests");
+
+#define bootverbose crypto_verbose
+static int crypto_verbose = 0;
+module_param(crypto_verbose, int, 0644);
+MODULE_PARM_DESC(crypto_verbose,
+               "Enable verbose crypto startup");
+
+int    crypto_usercrypto = 1;  /* userland may do crypto reqs */
+module_param(crypto_usercrypto, int, 0644);
+MODULE_PARM_DESC(crypto_usercrypto,
+          "Enable/disable user-mode access to crypto support");
+
+int    crypto_userasymcrypto = 1;      /* userland may do asym crypto reqs */
+module_param(crypto_userasymcrypto, int, 0644);
+MODULE_PARM_DESC(crypto_userasymcrypto,
+          "Enable/disable user-mode access to asymmetric crypto support");
+
+int    crypto_devallowsoft = 0;        /* only use hardware crypto */
+module_param(crypto_devallowsoft, int, 0644);
+MODULE_PARM_DESC(crypto_devallowsoft,
+          "Enable/disable use of software crypto support");
+
+static pid_t   cryptoproc = (pid_t) -1;
+static struct  completion cryptoproc_exited;
+static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
+static pid_t   cryptoretproc = (pid_t) -1;
+static struct  completion cryptoretproc_exited;
+static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
+
+static int crypto_proc(void *arg);
+static int crypto_ret_proc(void *arg);
+static int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
+static int crypto_kinvoke(struct cryptkop *krp, int flags);
+static void crypto_exit(void);
+static  int crypto_init(void);
+
+static struct cryptostats cryptostats;
+
+static struct cryptocap *
+crypto_checkdriver(u_int32_t hid)
+{
+       if (crypto_drivers == NULL)
+               return NULL;
+       return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
+}
+
+/*
+ * Compare a driver's list of supported algorithms against another
+ * list; return non-zero if all algorithms are supported.
+ */
+static int
+driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri)
+{
+       const struct cryptoini *cr;
+
+       /* See if all the algorithms are supported. */
+       for (cr = cri; cr; cr = cr->cri_next)
+               if (cap->cc_alg[cr->cri_alg] == 0)
+                       return 0;
+       return 1;
+}
+
+/*
+ * Select a driver for a new session that supports the specified
+ * algorithms and, optionally, is constrained according to the flags.
+ * The algorithm we use here is pretty stupid; just use the
+ * first driver that supports all the algorithms we need. If there
+ * are multiple drivers we choose the driver with the fewest active
+ * sessions.  We prefer hardware-backed drivers to software ones.
+ *
+ * XXX We need more smarts here (in real life too, but that's
+ * XXX another story altogether).
+ */
+static struct cryptocap *
+crypto_select_driver(const struct cryptoini *cri, int flags)
+{
+       struct cryptocap *cap, *best;
+       int match, hid;
+
+       CRYPTO_DRIVER_ASSERT();
+
+       /*
+        * Look first for hardware crypto devices if permitted.
+        */
+       if (flags & CRYPTOCAP_F_HARDWARE)
+               match = CRYPTOCAP_F_HARDWARE;
+       else
+               match = CRYPTOCAP_F_SOFTWARE;
+       best = NULL;
+again:
+       for (hid = 0; hid < crypto_drivers_num; hid++) {
+               cap = &crypto_drivers[hid];
+               /*
+                * If it's not initialized, is in the process of
+                * going away, or is not appropriate (hardware
+                * or software based on match), then skip.
+                */
+               if (cap->cc_dev == NULL ||
+                   (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
+                   (cap->cc_flags & match) == 0)
+                       continue;
+
+               /* verify all the algorithms are supported. */
+               if (driver_suitable(cap, cri)) {
+                       if (best == NULL ||
+                           cap->cc_sessions < best->cc_sessions)
+                               best = cap;
+               }
+       }
+       if (best != NULL)
+               return best;
+       if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
+               /* sort of an Algol 68-style for loop */
+               match = CRYPTOCAP_F_SOFTWARE;
+               goto again;
+       }
+       return best;
+}
+
+/*
+ * Create a new session.  The crid argument specifies a crypto
+ * driver to use or constraints on a driver to select (hardware
+ * only, software only, either).  Whatever driver is selected
+ * must be capable of the requested crypto algorithms.
+ */
+int
+crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid)
+{
+       struct cryptocap *cap;
+       u_int32_t hid, lid;
+       int err;
+       unsigned long d_flags;
+
+       CRYPTO_DRIVER_LOCK();
+       if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
+               /*
+                * Use specified driver; verify it is capable.
+                */
+               cap = crypto_checkdriver(crid);
+               if (cap != NULL && !driver_suitable(cap, cri))
+                       cap = NULL;
+       } else {
+               /*
+                * No requested driver; select based on crid flags.
+                */
+               cap = crypto_select_driver(cri, crid);
+               /*
+                * if NULL then can't do everything in one session.
+                * XXX Fix this. We need to inject a "virtual" session
+                * XXX layer right about here.
+                */
+       }
+       if (cap != NULL) {
+               /* Call the driver initialization routine. */
+               hid = cap - crypto_drivers;
+               lid = hid;              /* Pass the driver ID. */
+               cap->cc_sessions++;
+               CRYPTO_DRIVER_UNLOCK();
+               err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri);
+               CRYPTO_DRIVER_LOCK();
+               if (err == 0) {
+                       (*sid) = (cap->cc_flags & 0xff000000)
+                              | (hid & 0x00ffffff);
+                       (*sid) <<= 32;
+                       (*sid) |= (lid & 0xffffffff);
+               } else
+                       cap->cc_sessions--;
+       } else
+               err = EINVAL;
+       CRYPTO_DRIVER_UNLOCK();
+       return err;
+}
+
+static void
+crypto_remove(struct cryptocap *cap)
+{
+       CRYPTO_DRIVER_ASSERT();
+       if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
+               bzero(cap, sizeof(*cap));
+}
+
+/*
+ * Delete an existing session (or a reserved session on an unregistered
+ * driver).
+ */
+int
+crypto_freesession(u_int64_t sid)
+{
+       struct cryptocap *cap;
+       u_int32_t hid;
+       int err = 0;
+       unsigned long d_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+       CRYPTO_DRIVER_LOCK();
+
+       if (crypto_drivers == NULL) {
+               err = EINVAL;
+               goto done;
+       }
+
+       /* Determine two IDs. */
+       hid = CRYPTO_SESID2HID(sid);
+
+       if (hid >= crypto_drivers_num) {
+               dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid);
+               err = ENOENT;
+               goto done;
+       }
+       cap = &crypto_drivers[hid];
+
+       if (cap->cc_dev) {
+               CRYPTO_DRIVER_UNLOCK();
+               /* Call the driver cleanup routine, if available, unlocked. */
+               err = CRYPTODEV_FREESESSION(cap->cc_dev, sid);
+               CRYPTO_DRIVER_LOCK();
+       }
+
+       if (cap->cc_sessions)
+               cap->cc_sessions--;
+
+       if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
+               crypto_remove(cap);
+
+done:
+       CRYPTO_DRIVER_UNLOCK();
+       return err;
+}
+
+/*
+ * Return an unused driver id.  Used by drivers prior to registering
+ * support for the algorithms they handle.
+ */
+int32_t
+crypto_get_driverid(device_t dev, int flags)
+{
+       struct cryptocap *newdrv;
+       int i;
+       unsigned long d_flags;
+
+       if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
+               printf("%s: no flags specified when registering driver\n",
+                   device_get_nameunit(dev));
+               return -1;
+       }
+
+       CRYPTO_DRIVER_LOCK();
+
+       for (i = 0; i < crypto_drivers_num; i++) {
+               if (crypto_drivers[i].cc_dev == NULL &&
+                   (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
+                       break;
+               }
+       }
+
+       /* Out of entries, allocate some more. */
+       if (i == crypto_drivers_num) {
+               /* Be careful about wrap-around. */
+               if (2 * crypto_drivers_num <= crypto_drivers_num) {
+                       CRYPTO_DRIVER_UNLOCK();
+                       printk("crypto: driver count wraparound!\n");
+                       return -1;
+               }
+
+               newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap),
+                               GFP_KERNEL);
+               if (newdrv == NULL) {
+                       CRYPTO_DRIVER_UNLOCK();
+                       printk("crypto: no space to expand driver table!\n");
+                       return -1;
+               }
+
+               memcpy(newdrv, crypto_drivers,
+                               crypto_drivers_num * sizeof(struct cryptocap));
+               memset(&newdrv[crypto_drivers_num], 0,
+                               crypto_drivers_num * sizeof(struct cryptocap));
+
+               crypto_drivers_num *= 2;
+
+               kfree(crypto_drivers);
+               crypto_drivers = newdrv;
+       }
+
+       /* NB: state is zero'd on free */
+       crypto_drivers[i].cc_sessions = 1;      /* Mark */
+       crypto_drivers[i].cc_dev = dev;
+       crypto_drivers[i].cc_flags = flags;
+       if (bootverbose)
+               printf("crypto: assign %s driver id %u, flags %u\n",
+                   device_get_nameunit(dev), i, flags);
+
+       CRYPTO_DRIVER_UNLOCK();
+
+       return i;
+}
+
+/*
+ * Lookup a driver by name.  We match against the full device
+ * name and unit, and against just the name.  The latter gives
+ * us a simple widlcarding by device name.  On success return the
+ * driver/hardware identifier; otherwise return -1.
+ */
+int
+crypto_find_driver(const char *match)
+{
+       int i, len = strlen(match);
+       unsigned long d_flags;
+
+       CRYPTO_DRIVER_LOCK();
+       for (i = 0; i < crypto_drivers_num; i++) {
+               device_t dev = crypto_drivers[i].cc_dev;
+               if (dev == NULL ||
+                   (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP))
+                       continue;
+               if (strncmp(match, device_get_nameunit(dev), len) == 0 ||
+                   strncmp(match, device_get_name(dev), len) == 0)
+                       break;
+       }
+       CRYPTO_DRIVER_UNLOCK();
+       return i < crypto_drivers_num ? i : -1;
+}
+
+/*
+ * Return the device_t for the specified driver or NULL
+ * if the driver identifier is invalid.
+ */
+device_t
+crypto_find_device_byhid(int hid)
+{
+       struct cryptocap *cap = crypto_checkdriver(hid);
+       return cap != NULL ? cap->cc_dev : NULL;
+}
+
+/*
+ * Return the device/driver capabilities.
+ */
+int
+crypto_getcaps(int hid)
+{
+       struct cryptocap *cap = crypto_checkdriver(hid);
+       return cap != NULL ? cap->cc_flags : 0;
+}
+
+/*
+ * Register support for a key-related algorithm.  This routine
+ * is called once for each algorithm supported a driver.
+ */
+int
+crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags)
+{
+       struct cryptocap *cap;
+       int err;
+       unsigned long d_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+       CRYPTO_DRIVER_LOCK();
+
+       cap = crypto_checkdriver(driverid);
+       if (cap != NULL &&
+           (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
+               /*
+                * XXX Do some performance testing to determine placing.
+                * XXX We probably need an auxiliary data structure that
+                * XXX describes relative performances.
+                */
+
+               cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
+               if (bootverbose)
+                       printf("crypto: %s registers key alg %u flags %u\n"
+                               , device_get_nameunit(cap->cc_dev)
+                               , kalg
+                               , flags
+                       );
+               err = 0;
+       } else
+               err = EINVAL;
+
+       CRYPTO_DRIVER_UNLOCK();
+       return err;
+}
+
+/*
+ * Register support for a non-key-related algorithm.  This routine
+ * is called once for each such algorithm supported by a driver.
+ */
+int
+crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
+    u_int32_t flags)
+{
+       struct cryptocap *cap;
+       int err;
+       unsigned long d_flags;
+
+       dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__,
+                       driverid, alg, maxoplen, flags);
+
+       CRYPTO_DRIVER_LOCK();
+
+       cap = crypto_checkdriver(driverid);
+       /* NB: algorithms are in the range [1..max] */
+       if (cap != NULL &&
+           (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
+               /*
+                * XXX Do some performance testing to determine placing.
+                * XXX We probably need an auxiliary data structure that
+                * XXX describes relative performances.
+                */
+
+               cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
+               cap->cc_max_op_len[alg] = maxoplen;
+               if (bootverbose)
+                       printf("crypto: %s registers alg %u flags %u maxoplen %u\n"
+                               , device_get_nameunit(cap->cc_dev)
+                               , alg
+                               , flags
+                               , maxoplen
+                       );
+               cap->cc_sessions = 0;           /* Unmark */
+               err = 0;
+       } else
+               err = EINVAL;
+
+       CRYPTO_DRIVER_UNLOCK();
+       return err;
+}
+
+static void
+driver_finis(struct cryptocap *cap)
+{
+       u_int32_t ses, kops;
+
+       CRYPTO_DRIVER_ASSERT();
+
+       ses = cap->cc_sessions;
+       kops = cap->cc_koperations;
+       bzero(cap, sizeof(*cap));
+       if (ses != 0 || kops != 0) {
+               /*
+                * If there are pending sessions,
+                * just mark as invalid.
+                */
+               cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
+               cap->cc_sessions = ses;
+               cap->cc_koperations = kops;
+       }
+}
+
+/*
+ * Unregister a crypto driver. If there are pending sessions using it,
+ * leave enough information around so that subsequent calls using those
+ * sessions will correctly detect the driver has been unregistered and
+ * reroute requests.
+ */
+int
+crypto_unregister(u_int32_t driverid, int alg)
+{
+       struct cryptocap *cap;
+       int i, err;
+       unsigned long d_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+       CRYPTO_DRIVER_LOCK();
+
+       cap = crypto_checkdriver(driverid);
+       if (cap != NULL &&
+           (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
+           cap->cc_alg[alg] != 0) {
+               cap->cc_alg[alg] = 0;
+               cap->cc_max_op_len[alg] = 0;
+
+               /* Was this the last algorithm ? */
+               for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
+                       if (cap->cc_alg[i] != 0)
+                               break;
+
+               if (i == CRYPTO_ALGORITHM_MAX + 1)
+                       driver_finis(cap);
+               err = 0;
+       } else
+               err = EINVAL;
+       CRYPTO_DRIVER_UNLOCK();
+       return err;
+}
+
+/*
+ * Unregister all algorithms associated with a crypto driver.
+ * If there are pending sessions using it, leave enough information
+ * around so that subsequent calls using those sessions will
+ * correctly detect the driver has been unregistered and reroute
+ * requests.
+ */
+int
+crypto_unregister_all(u_int32_t driverid)
+{
+       struct cryptocap *cap;
+       int err;
+       unsigned long d_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+       CRYPTO_DRIVER_LOCK();
+       cap = crypto_checkdriver(driverid);
+       if (cap != NULL) {
+               driver_finis(cap);
+               err = 0;
+       } else
+               err = EINVAL;
+       CRYPTO_DRIVER_UNLOCK();
+
+       return err;
+}
+
+/*
+ * Clear blockage on a driver.  The what parameter indicates whether
+ * the driver is now ready for cryptop's and/or cryptokop's.
+ */
+int
+crypto_unblock(u_int32_t driverid, int what)
+{
+       struct cryptocap *cap;
+       int err;
+       unsigned long q_flags;
+
+       CRYPTO_Q_LOCK();
+       cap = crypto_checkdriver(driverid);
+       if (cap != NULL) {
+               if (what & CRYPTO_SYMQ) {
+                       cap->cc_qblocked = 0;
+                       crypto_all_qblocked = 0;
+               }
+               if (what & CRYPTO_ASYMQ) {
+                       cap->cc_kqblocked = 0;
+                       crypto_all_kqblocked = 0;
+               }
+               if (crp_sleep)
+                       wake_up_interruptible(&cryptoproc_wait);
+               err = 0;
+       } else
+               err = EINVAL;
+       CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock
+
+       return err;
+}
+
+/*
+ * Add a crypto request to a queue, to be processed by the kernel thread.
+ */
+int
+crypto_dispatch(struct cryptop *crp)
+{
+       struct cryptocap *cap;
+       int result = -1;
+       unsigned long q_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+
+       cryptostats.cs_ops++;
+
+       CRYPTO_Q_LOCK();
+       if (crypto_q_cnt >= crypto_q_max) {
+               CRYPTO_Q_UNLOCK();
+               cryptostats.cs_drops++;
+               return ENOMEM;
+       }
+       crypto_q_cnt++;
+
+       /*
+        * Caller marked the request to be processed immediately; dispatch
+        * it directly to the driver unless the driver is currently blocked.
+        */
+       if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
+               int hid = CRYPTO_SESID2HID(crp->crp_sid);
+               cap = crypto_checkdriver(hid);
+               /* Driver cannot disappear when there is an active session. */
+               KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
+               if (!cap->cc_qblocked) {
+                       crypto_all_qblocked = 0;
+                       crypto_drivers[hid].cc_qblocked = 1;
+                       CRYPTO_Q_UNLOCK();
+                       result = crypto_invoke(cap, crp, 0);
+                       CRYPTO_Q_LOCK();
+                       if (result != ERESTART)
+                               crypto_drivers[hid].cc_qblocked = 0;
+               }
+       }
+       if (result == ERESTART) {
+               /*
+                * The driver ran out of resources, mark the
+                * driver ``blocked'' for cryptop's and put
+                * the request back in the queue.  It would
+                * best to put the request back where we got
+                * it but that's hard so for now we put it
+                * at the front.  This should be ok; putting
+                * it at the end does not work.
+                */
+               list_add(&crp->crp_next, &crp_q);
+               cryptostats.cs_blocks++;
+       } else if (result == -1) {
+               TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
+       }
+       if (crp_sleep)
+               wake_up_interruptible(&cryptoproc_wait);
+       CRYPTO_Q_UNLOCK();
+       return 0;
+}
+
+/*
+ * Add an asymetric crypto request to a queue,
+ * to be processed by the kernel thread.
+ */
+int
+crypto_kdispatch(struct cryptkop *krp)
+{
+       int error;
+       unsigned long q_flags;
+
+       cryptostats.cs_kops++;
+
+       error = crypto_kinvoke(krp, krp->krp_crid);
+       if (error == ERESTART) {
+               CRYPTO_Q_LOCK();
+               TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
+               if (crp_sleep)
+                       wake_up_interruptible(&cryptoproc_wait);
+               CRYPTO_Q_UNLOCK();
+               error = 0;
+       }
+       return error;
+}
+
+/*
+ * Verify a driver is suitable for the specified operation.
+ */
+static __inline int
+kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp)
+{
+       return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0;
+}
+
+/*
+ * Select a driver for an asym operation.  The driver must
+ * support the necessary algorithm.  The caller can constrain
+ * which device is selected with the flags parameter.  The
+ * algorithm we use here is pretty stupid; just use the first
+ * driver that supports the algorithms we need. If there are
+ * multiple suitable drivers we choose the driver with the
+ * fewest active operations.  We prefer hardware-backed
+ * drivers to software ones when either may be used.
+ */
+static struct cryptocap *
+crypto_select_kdriver(const struct cryptkop *krp, int flags)
+{
+       struct cryptocap *cap, *best, *blocked;
+       int match, hid;
+
+       CRYPTO_DRIVER_ASSERT();
+
+       /*
+        * Look first for hardware crypto devices if permitted.
+        */
+       if (flags & CRYPTOCAP_F_HARDWARE)
+               match = CRYPTOCAP_F_HARDWARE;
+       else
+               match = CRYPTOCAP_F_SOFTWARE;
+       best = NULL;
+       blocked = NULL;
+again:
+       for (hid = 0; hid < crypto_drivers_num; hid++) {
+               cap = &crypto_drivers[hid];
+               /*
+                * If it's not initialized, is in the process of
+                * going away, or is not appropriate (hardware
+                * or software based on match), then skip.
+                */
+               if (cap->cc_dev == NULL ||
+                   (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
+                   (cap->cc_flags & match) == 0)
+                       continue;
+
+               /* verify all the algorithms are supported. */
+               if (kdriver_suitable(cap, krp)) {
+                       if (best == NULL ||
+                           cap->cc_koperations < best->cc_koperations)
+                               best = cap;
+               }
+       }
+       if (best != NULL)
+               return best;
+       if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
+               /* sort of an Algol 68-style for loop */
+               match = CRYPTOCAP_F_SOFTWARE;
+               goto again;
+       }
+       return best;
+}
+
+/*
+ * Dispatch an assymetric crypto request.
+ */
+static int
+crypto_kinvoke(struct cryptkop *krp, int crid)
+{
+       struct cryptocap *cap = NULL;
+       int error;
+       unsigned long d_flags;
+
+       KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
+       KASSERT(krp->krp_callback != NULL,
+           ("%s: krp->crp_callback == NULL", __func__));
+
+       CRYPTO_DRIVER_LOCK();
+       if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
+               cap = crypto_checkdriver(crid);
+               if (cap != NULL) {
+                       /*
+                        * Driver present, it must support the necessary
+                        * algorithm and, if s/w drivers are excluded,
+                        * it must be registered as hardware-backed.
+                        */
+                       if (!kdriver_suitable(cap, krp) ||
+                           (!crypto_devallowsoft &&
+                            (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0))
+                               cap = NULL;
+               }
+       } else {
+               /*
+                * No requested driver; select based on crid flags.
+                */
+               if (!crypto_devallowsoft)       /* NB: disallow s/w drivers */
+                       crid &= ~CRYPTOCAP_F_SOFTWARE;
+               cap = crypto_select_kdriver(krp, crid);
+       }
+       if (cap != NULL && !cap->cc_kqblocked) {
+               krp->krp_hid = cap - crypto_drivers;
+               cap->cc_koperations++;
+               CRYPTO_DRIVER_UNLOCK();
+               error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0);
+               CRYPTO_DRIVER_LOCK();
+               if (error == ERESTART) {
+                       cap->cc_koperations--;
+                       CRYPTO_DRIVER_UNLOCK();
+                       return (error);
+               }
+               /* return the actual device used */
+               krp->krp_crid = krp->krp_hid;
+       } else {
+               /*
+                * NB: cap is !NULL if device is blocked; in
+                *     that case return ERESTART so the operation
+                *     is resubmitted if possible.
+                */
+               error = (cap == NULL) ? ENODEV : ERESTART;
+       }
+       CRYPTO_DRIVER_UNLOCK();
+
+       if (error) {
+               krp->krp_status = error;
+               crypto_kdone(krp);
+       }
+       return 0;
+}
+
+
+/*
+ * Dispatch a crypto request to the appropriate crypto devices.
+ */
+static int
+crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
+{
+       KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
+       KASSERT(crp->crp_callback != NULL,
+           ("%s: crp->crp_callback == NULL", __func__));
+       KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
+
+       dprintk("%s()\n", __FUNCTION__);
+
+#ifdef CRYPTO_TIMING
+       if (crypto_timing)
+               crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
+#endif
+       if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
+               struct cryptodesc *crd;
+               u_int64_t nid;
+
+               /*
+                * Driver has unregistered; migrate the session and return
+                * an error to the caller so they'll resubmit the op.
+                *
+                * XXX: What if there are more already queued requests for this
+                *      session?
+                */
+               crypto_freesession(crp->crp_sid);
+
+               for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
+                       crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
+
+               /* XXX propagate flags from initial session? */
+               if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI),
+                   CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0)
+                       crp->crp_sid = nid;
+
+               crp->crp_etype = EAGAIN;
+               crypto_done(crp);
+               return 0;
+       } else {
+               /*
+                * Invoke the driver to process the request.
+                */
+               return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint);
+       }
+}
+
+/*
+ * Release a set of crypto descriptors.
+ */
+void
+crypto_freereq(struct cryptop *crp)
+{
+       struct cryptodesc *crd;
+
+       if (crp == NULL)
+               return;
+
+#ifdef DIAGNOSTIC
+       {
+               struct cryptop *crp2;
+               unsigned long q_flags;
+
+               CRYPTO_Q_LOCK();
+               TAILQ_FOREACH(crp2, &crp_q, crp_next) {
+                       KASSERT(crp2 != crp,
+                           ("Freeing cryptop from the crypto queue (%p).",
+                           crp));
+               }
+               CRYPTO_Q_UNLOCK();
+               CRYPTO_RETQ_LOCK();
+               TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) {
+                       KASSERT(crp2 != crp,
+                           ("Freeing cryptop from the return queue (%p).",
+                           crp));
+               }
+               CRYPTO_RETQ_UNLOCK();
+       }
+#endif
+
+       while ((crd = crp->crp_desc) != NULL) {
+               crp->crp_desc = crd->crd_next;
+               kmem_cache_free(cryptodesc_zone, crd);
+       }
+       kmem_cache_free(cryptop_zone, crp);
+}
+
+/*
+ * Acquire a set of crypto descriptors.
+ */
+struct cryptop *
+crypto_getreq(int num)
+{
+       struct cryptodesc *crd;
+       struct cryptop *crp;
+
+       crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC);
+       if (crp != NULL) {
+               memset(crp, 0, sizeof(*crp));
+               INIT_LIST_HEAD(&crp->crp_next);
+               init_waitqueue_head(&crp->crp_waitq);
+               while (num--) {
+                       crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC);
+                       if (crd == NULL) {
+                               crypto_freereq(crp);
+                               return NULL;
+                       }
+                       memset(crd, 0, sizeof(*crd));
+                       crd->crd_next = crp->crp_desc;
+                       crp->crp_desc = crd;
+               }
+       }
+       return crp;
+}
+
+/*
+ * Invoke the callback on behalf of the driver.
+ */
+void
+crypto_done(struct cryptop *crp)
+{
+       unsigned long q_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+       if ((crp->crp_flags & CRYPTO_F_DONE) == 0) {
+               crp->crp_flags |= CRYPTO_F_DONE;
+               CRYPTO_Q_LOCK();
+               crypto_q_cnt--;
+               CRYPTO_Q_UNLOCK();
+       } else
+               printk("crypto: crypto_done op already done, flags 0x%x",
+                               crp->crp_flags);
+       if (crp->crp_etype != 0)
+               cryptostats.cs_errs++;
+       /*
+        * CBIMM means unconditionally do the callback immediately;
+        * CBIFSYNC means do the callback immediately only if the
+        * operation was done synchronously.  Both are used to avoid
+        * doing extraneous context switches; the latter is mostly
+        * used with the software crypto driver.
+        */
+       if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
+           ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
+            (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
+               /*
+                * 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).
+                */
+               crp->crp_callback(crp);
+       } else {
+               unsigned long r_flags;
+               /*
+                * Normal case; queue the callback for the thread.
+                */
+               CRYPTO_RETQ_LOCK();
+               if (CRYPTO_RETQ_EMPTY())
+                       wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
+               TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
+               CRYPTO_RETQ_UNLOCK();
+       }
+}
+
+/*
+ * Invoke the callback on behalf of the driver.
+ */
+void
+crypto_kdone(struct cryptkop *krp)
+{
+       struct cryptocap *cap;
+       unsigned long d_flags;
+
+       if ((krp->krp_flags & CRYPTO_KF_DONE) != 0)
+               printk("crypto: crypto_kdone op already done, flags 0x%x",
+                               krp->krp_flags);
+       krp->krp_flags |= CRYPTO_KF_DONE;
+       if (krp->krp_status != 0)
+               cryptostats.cs_kerrs++;
+
+       CRYPTO_DRIVER_LOCK();
+       /* XXX: What if driver is loaded in the meantime? */
+       if (krp->krp_hid < crypto_drivers_num) {
+               cap = &crypto_drivers[krp->krp_hid];
+               cap->cc_koperations--;
+               KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
+               if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
+                       crypto_remove(cap);
+       }
+       CRYPTO_DRIVER_UNLOCK();
+
+       /*
+        * CBIMM means unconditionally do the callback immediately;
+        * This is used to avoid doing extraneous context switches
+        */
+       if ((krp->krp_flags & CRYPTO_KF_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).
+                */
+               krp->krp_callback(krp);
+       } else {
+               unsigned long r_flags;
+               /*
+                * Normal case; queue the callback for the thread.
+                */
+               CRYPTO_RETQ_LOCK();
+               if (CRYPTO_RETQ_EMPTY())
+                       wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
+               TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
+               CRYPTO_RETQ_UNLOCK();
+       }
+}
+
+int
+crypto_getfeat(int *featp)
+{
+       int hid, kalg, feat = 0;
+       unsigned long d_flags;
+
+       CRYPTO_DRIVER_LOCK();
+       for (hid = 0; hid < crypto_drivers_num; hid++) {
+               const struct cryptocap *cap = &crypto_drivers[hid];
+
+               if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
+                   !crypto_devallowsoft) {
+                       continue;
+               }
+               for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
+                       if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED)
+                               feat |=  1 << kalg;
+       }
+       CRYPTO_DRIVER_UNLOCK();
+       *featp = feat;
+       return (0);
+}
+
+/*
+ * Crypto thread, dispatches crypto requests.
+ */
+static int
+crypto_proc(void *arg)
+{
+       struct cryptop *crp, *submit;
+       struct cryptkop *krp, *krpp;
+       struct cryptocap *cap;
+       u_int32_t hid;
+       int result, hint;
+       unsigned long q_flags;
+
+       ocf_daemonize("crypto");
+
+       CRYPTO_Q_LOCK();
+       for (;;) {
+               /*
+                * we need to make sure we don't get into a busy loop with nothing
+                * to do,  the two crypto_all_*blocked vars help us find out when
+                * we are all full and can do nothing on any driver or Q.  If so we
+                * wait for an unblock.
+                */
+               crypto_all_qblocked  = !list_empty(&crp_q);
+
+               /*
+                * Find the first element in the queue that can be
+                * processed and look-ahead to see if multiple ops
+                * are ready for the same driver.
+                */
+               submit = NULL;
+               hint = 0;
+               list_for_each_entry(crp, &crp_q, crp_next) {
+                       hid = CRYPTO_SESID2HID(crp->crp_sid);
+                       cap = crypto_checkdriver(hid);
+                       /*
+                        * Driver cannot disappear when there is an active
+                        * session.
+                        */
+                       KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
+                           __func__, __LINE__));
+                       if (cap == NULL || cap->cc_dev == NULL) {
+                               /* Op needs to be migrated, process it. */
+                               if (submit == NULL)
+                                       submit = crp;
+                               break;
+                       }
+                       if (!cap->cc_qblocked) {
+                               if (submit != NULL) {
+                                       /*
+                                        * We stop on finding another op,
+                                        * regardless whether its for the same
+                                        * driver or not.  We could keep
+                                        * searching the queue but it might be
+                                        * better to just use a per-driver
+                                        * queue instead.
+                                        */
+                                       if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
+                                               hint = CRYPTO_HINT_MORE;
+                                       break;
+                               } else {
+                                       submit = crp;
+                                       if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
+                                               break;
+                                       /* keep scanning for more are q'd */
+                               }
+                       }
+               }
+               if (submit != NULL) {
+                       hid = CRYPTO_SESID2HID(submit->crp_sid);
+                       crypto_all_qblocked = 0;
+                       list_del(&submit->crp_next);
+                       crypto_drivers[hid].cc_qblocked = 1;
+                       cap = crypto_checkdriver(hid);
+                       CRYPTO_Q_UNLOCK();
+                       KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
+                           __func__, __LINE__));
+                       result = crypto_invoke(cap, submit, hint);
+                       CRYPTO_Q_LOCK();
+                       if (result == ERESTART) {
+                               /*
+                                * The driver ran out of resources, mark the
+                                * driver ``blocked'' for cryptop's and put
+                                * the request back in the queue.  It would
+                                * best to put the request back where we got
+                                * it but that's hard so for now we put it
+                                * at the front.  This should be ok; putting
+                                * it at the end does not work.
+                                */
+                               /* XXX validate sid again? */
+                               list_add(&submit->crp_next, &crp_q);
+                               cryptostats.cs_blocks++;
+                       } else
+                               crypto_drivers[hid].cc_qblocked=0;
+               }
+
+               crypto_all_kqblocked = !list_empty(&crp_kq);
+
+               /* As above, but for key ops */
+               krp = NULL;
+               list_for_each_entry(krpp, &crp_kq, krp_next) {
+                       cap = crypto_checkdriver(krpp->krp_hid);
+                       if (cap == NULL || cap->cc_dev == NULL) {
+                               /*
+                                * Operation needs to be migrated, invalidate
+                                * the assigned device so it will reselect a
+                                * new one below.  Propagate the original
+                                * crid selection flags if supplied.
+                                */
+                               krp->krp_hid = krp->krp_crid &
+                                   (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE);
+                               if (krp->krp_hid == 0)
+                                       krp->krp_hid =
+                                   CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE;
+                               break;
+                       }
+                       if (!cap->cc_kqblocked) {
+                               krp = krpp;
+                               break;
+                       }
+               }
+               if (krp != NULL) {
+                       crypto_all_kqblocked = 0;
+                       list_del(&krp->krp_next);
+                       crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
+                       CRYPTO_Q_UNLOCK();
+                       result = crypto_kinvoke(krp, krp->krp_hid);
+                       CRYPTO_Q_LOCK();
+                       if (result == ERESTART) {
+                               /*
+                                * The driver ran out of resources, mark the
+                                * driver ``blocked'' for cryptkop's and put
+                                * the request back in the queue.  It would
+                                * best to put the request back where we got
+                                * it but that's hard so for now we put it
+                                * at the front.  This should be ok; putting
+                                * it at the end does not work.
+                                */
+                               /* XXX validate sid again? */
+                               list_add(&krp->krp_next, &crp_kq);
+                               cryptostats.cs_kblocks++;
+                       } else
+                               crypto_drivers[krp->krp_hid].cc_kqblocked = 0;
+               }
+
+               if (submit == NULL && krp == NULL) {
+                       /*
+                        * Nothing more to be processed.  Sleep until we're
+                        * woken because there are more ops to process.
+                        * This happens either by submission or by a driver
+                        * becoming unblocked and notifying us through
+                        * crypto_unblock.  Note that when we wakeup we
+                        * start processing each queue again from the
+                        * front. It's not clear that it's important to
+                        * preserve this ordering since ops may finish
+                        * out of order if dispatched to different devices
+                        * and some become blocked while others do not.
+                        */
+                       dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n",
+                                       __FUNCTION__,
+                                       list_empty(&crp_q), crypto_all_qblocked,
+                                       list_empty(&crp_kq), crypto_all_kqblocked);
+                       CRYPTO_Q_UNLOCK();
+                       crp_sleep = 1;
+                       wait_event_interruptible(cryptoproc_wait,
+                                       !(list_empty(&crp_q) || crypto_all_qblocked) ||
+                                       !(list_empty(&crp_kq) || crypto_all_kqblocked) ||
+                                       cryptoproc == (pid_t) -1);
+                       crp_sleep = 0;
+                       if (signal_pending (current)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                               spin_lock_irq(&current->sigmask_lock);
+#endif
+                               flush_signals(current);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                               spin_unlock_irq(&current->sigmask_lock);
+#endif
+                       }
+                       CRYPTO_Q_LOCK();
+                       dprintk("%s - awake\n", __FUNCTION__);
+                       if (cryptoproc == (pid_t) -1)
+                               break;
+                       cryptostats.cs_intrs++;
+               }
+       }
+       CRYPTO_Q_UNLOCK();
+       complete_and_exit(&cryptoproc_exited, 0);
+}
+
+/*
+ * Crypto returns thread, does callbacks for processed crypto requests.
+ * Callbacks are done here, rather than in the crypto drivers, because
+ * callbacks typically are expensive and would slow interrupt handling.
+ */
+static int
+crypto_ret_proc(void *arg)
+{
+       struct cryptop *crpt;
+       struct cryptkop *krpt;
+       unsigned long  r_flags;
+
+       ocf_daemonize("crypto_ret");
+
+       CRYPTO_RETQ_LOCK();
+       for (;;) {
+               /* Harvest return q's for completed ops */
+               crpt = NULL;
+               if (!list_empty(&crp_ret_q))
+                       crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next);
+               if (crpt != NULL)
+                       list_del(&crpt->crp_next);
+
+               krpt = NULL;
+               if (!list_empty(&crp_ret_kq))
+                       krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next);
+               if (krpt != NULL)
+                       list_del(&krpt->krp_next);
+
+               if (crpt != NULL || krpt != NULL) {
+                       CRYPTO_RETQ_UNLOCK();
+                       /*
+                        * Run callbacks unlocked.
+                        */
+                       if (crpt != NULL)
+                               crpt->crp_callback(crpt);
+                       if (krpt != NULL)
+                               krpt->krp_callback(krpt);
+                       CRYPTO_RETQ_LOCK();
+               } else {
+                       /*
+                        * Nothing more to be processed.  Sleep until we're
+                        * woken because there are more returns to process.
+                        */
+                       dprintk("%s - sleeping\n", __FUNCTION__);
+                       CRYPTO_RETQ_UNLOCK();
+                       wait_event_interruptible(cryptoretproc_wait,
+                                       cryptoretproc == (pid_t) -1 ||
+                                       !list_empty(&crp_ret_q) ||
+                                       !list_empty(&crp_ret_kq));
+                       if (signal_pending (current)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                               spin_lock_irq(&current->sigmask_lock);
+#endif
+                               flush_signals(current);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                               spin_unlock_irq(&current->sigmask_lock);
+#endif
+                       }
+                       CRYPTO_RETQ_LOCK();
+                       dprintk("%s - awake\n", __FUNCTION__);
+                       if (cryptoretproc == (pid_t) -1) {
+                               dprintk("%s - EXITING!\n", __FUNCTION__);
+                               break;
+                       }
+                       cryptostats.cs_rets++;
+               }
+       }
+       CRYPTO_RETQ_UNLOCK();
+       complete_and_exit(&cryptoretproc_exited, 0);
+}
+
+
+#if 0 /* should put this into /proc or something */
+static void
+db_show_drivers(void)
+{
+       int hid;
+
+       db_printf("%12s %4s %4s %8s %2s %2s\n"
+               , "Device"
+               , "Ses"
+               , "Kops"
+               , "Flags"
+               , "QB"
+               , "KB"
+       );
+       for (hid = 0; hid < crypto_drivers_num; hid++) {
+               const struct cryptocap *cap = &crypto_drivers[hid];
+               if (cap->cc_dev == NULL)
+                       continue;
+               db_printf("%-12s %4u %4u %08x %2u %2u\n"
+                   , device_get_nameunit(cap->cc_dev)
+                   , cap->cc_sessions
+                   , cap->cc_koperations
+                   , cap->cc_flags
+                   , cap->cc_qblocked
+                   , cap->cc_kqblocked
+               );
+       }
+}
+
+DB_SHOW_COMMAND(crypto, db_show_crypto)
+{
+       struct cryptop *crp;
+
+       db_show_drivers();
+       db_printf("\n");
+
+       db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n",
+           "HID", "Caps", "Ilen", "Olen", "Etype", "Flags",
+           "Desc", "Callback");
+       TAILQ_FOREACH(crp, &crp_q, crp_next) {
+               db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n"
+                   , (int) CRYPTO_SESID2HID(crp->crp_sid)
+                   , (int) CRYPTO_SESID2CAPS(crp->crp_sid)
+                   , crp->crp_ilen, crp->crp_olen
+                   , crp->crp_etype
+                   , crp->crp_flags
+                   , crp->crp_desc
+                   , crp->crp_callback
+               );
+       }
+       if (!TAILQ_EMPTY(&crp_ret_q)) {
+               db_printf("\n%4s %4s %4s %8s\n",
+                   "HID", "Etype", "Flags", "Callback");
+               TAILQ_FOREACH(crp, &crp_ret_q, crp_next) {
+                       db_printf("%4u %4u %04x %8p\n"
+                           , (int) CRYPTO_SESID2HID(crp->crp_sid)
+                           , crp->crp_etype
+                           , crp->crp_flags
+                           , crp->crp_callback
+                       );
+               }
+       }
+}
+
+DB_SHOW_COMMAND(kcrypto, db_show_kcrypto)
+{
+       struct cryptkop *krp;
+
+       db_show_drivers();
+       db_printf("\n");
+
+       db_printf("%4s %5s %4s %4s %8s %4s %8s\n",
+           "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback");
+       TAILQ_FOREACH(krp, &crp_kq, krp_next) {
+               db_printf("%4u %5u %4u %4u %08x %4u %8p\n"
+                   , krp->krp_op
+                   , krp->krp_status
+                   , krp->krp_iparams, krp->krp_oparams
+                   , krp->krp_crid, krp->krp_hid
+                   , krp->krp_callback
+               );
+       }
+       if (!TAILQ_EMPTY(&crp_ret_q)) {
+               db_printf("%4s %5s %8s %4s %8s\n",
+                   "Op", "Status", "CRID", "HID", "Callback");
+               TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) {
+                       db_printf("%4u %5u %08x %4u %8p\n"
+                           , krp->krp_op
+                           , krp->krp_status
+                           , krp->krp_crid, krp->krp_hid
+                           , krp->krp_callback
+                       );
+               }
+       }
+}
+#endif
+
+
+static int
+crypto_init(void)
+{
+       int error;
+
+       dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init);
+
+       if (crypto_initted)
+               return 0;
+       crypto_initted = 1;
+
+       spin_lock_init(&crypto_drivers_lock);
+       spin_lock_init(&crypto_q_lock);
+       spin_lock_init(&crypto_ret_q_lock);
+
+       cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop),
+                                      0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+                                      , NULL
+#endif
+                                       );
+
+       cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc),
+                                      0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+                                      , NULL
+#endif
+                                       );
+
+       if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
+               printk("crypto: crypto_init cannot setup crypto zones\n");
+               error = ENOMEM;
+               goto bad;
+       }
+
+       crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
+       crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap),
+                       GFP_KERNEL);
+       if (crypto_drivers == NULL) {
+               printk("crypto: crypto_init cannot setup crypto drivers\n");
+               error = ENOMEM;
+               goto bad;
+       }
+
+       memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap));
+
+       init_completion(&cryptoproc_exited);
+       init_completion(&cryptoretproc_exited);
+
+       cryptoproc = 0; /* to avoid race condition where proc runs first */
+       cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES);
+       if (cryptoproc < 0) {
+               error = cryptoproc;
+               printk("crypto: crypto_init cannot start crypto thread; error %d",
+                       error);
+               goto bad;
+       }
+
+       cryptoretproc = 0; /* to avoid race condition where proc runs first */
+       cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES);
+       if (cryptoretproc < 0) {
+               error = cryptoretproc;
+               printk("crypto: crypto_init cannot start cryptoret thread; error %d",
+                               error);
+               goto bad;
+       }
+
+       return 0;
+bad:
+       crypto_exit();
+       return error;
+}
+
+
+static void
+crypto_exit(void)
+{
+       pid_t p;
+       unsigned long d_flags;
+
+       dprintk("%s()\n", __FUNCTION__);
+
+       /*
+        * Terminate any crypto threads.
+        */
+
+       CRYPTO_DRIVER_LOCK();
+       p = cryptoproc;
+       cryptoproc = (pid_t) -1;
+       kill_proc(p, SIGTERM, 1);
+       wake_up_interruptible(&cryptoproc_wait);
+       CRYPTO_DRIVER_UNLOCK();
+
+       wait_for_completion(&cryptoproc_exited);
+
+       CRYPTO_DRIVER_LOCK();
+       p = cryptoretproc;
+       cryptoretproc = (pid_t) -1;
+       kill_proc(p, SIGTERM, 1);
+       wake_up_interruptible(&cryptoretproc_wait);
+       CRYPTO_DRIVER_UNLOCK();
+
+       wait_for_completion(&cryptoretproc_exited);
+
+       /* XXX flush queues??? */
+
+       /* 
+        * Reclaim dynamically allocated resources.
+        */
+       if (crypto_drivers != NULL)
+               kfree(crypto_drivers);
+
+       if (cryptodesc_zone != NULL)
+               kmem_cache_destroy(cryptodesc_zone);
+       if (cryptop_zone != NULL)
+               kmem_cache_destroy(cryptop_zone);
+}
+
+
+EXPORT_SYMBOL(crypto_newsession);
+EXPORT_SYMBOL(crypto_freesession);
+EXPORT_SYMBOL(crypto_get_driverid);
+EXPORT_SYMBOL(crypto_kregister);
+EXPORT_SYMBOL(crypto_register);
+EXPORT_SYMBOL(crypto_unregister);
+EXPORT_SYMBOL(crypto_unregister_all);
+EXPORT_SYMBOL(crypto_unblock);
+EXPORT_SYMBOL(crypto_dispatch);
+EXPORT_SYMBOL(crypto_kdispatch);
+EXPORT_SYMBOL(crypto_freereq);
+EXPORT_SYMBOL(crypto_getreq);
+EXPORT_SYMBOL(crypto_done);
+EXPORT_SYMBOL(crypto_kdone);
+EXPORT_SYMBOL(crypto_getfeat);
+EXPORT_SYMBOL(crypto_userasymcrypto);
+EXPORT_SYMBOL(crypto_getcaps);
+EXPORT_SYMBOL(crypto_find_driver);
+EXPORT_SYMBOL(crypto_find_device_byhid);
+
+module_init(crypto_init);
+module_exit(crypto_exit);
+
+MODULE_LICENSE("BSD");
+MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
+MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)");
diff --git a/target/linux/generic-2.6/files/crypto/ocf/cryptodev.c b/target/linux/generic-2.6/files/crypto/ocf/cryptodev.c
new file mode 100644 (file)
index 0000000..13d57a1
--- /dev/null
@@ -0,0 +1,1048 @@
+/*     $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $  */
+
+/*-
+ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2006-2007 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * Copyright (c) 2001 Theo de Raadt
+ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $");
+ */
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/unistd.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/miscdevice.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <cryptodev.h>
+#include <uio.h>
+
+extern asmlinkage long sys_dup(unsigned int fildes);
+
+#define debug cryptodev_debug
+int cryptodev_debug = 0;
+module_param(cryptodev_debug, int, 0644);
+MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug");
+
+struct csession_info {
+       u_int16_t       blocksize;
+       u_int16_t       minkey, maxkey;
+
+       u_int16_t       keysize;
+       /* u_int16_t    hashsize;  */
+       u_int16_t       authsize;
+       /* u_int16_t    ctxsize; */
+};
+
+struct csession {
+       struct list_head        list;
+       u_int64_t       sid;
+       u_int32_t       ses;
+
+       wait_queue_head_t waitq;
+
+       u_int32_t       cipher;
+
+       u_int32_t       mac;
+
+       caddr_t         key;
+       int             keylen;
+       u_char          tmp_iv[EALG_MAX_BLOCK_LEN];
+
+       caddr_t         mackey;
+       int             mackeylen;
+
+       struct csession_info info;
+
+       struct iovec    iovec;
+       struct uio      uio;
+       int             error;
+};
+
+struct fcrypt {
+       struct list_head        csessions;
+       int             sesn;
+};
+
+static struct csession *csefind(struct fcrypt *, u_int);
+static int csedelete(struct fcrypt *, struct csession *);
+static struct csession *cseadd(struct fcrypt *, struct csession *);
+static struct csession *csecreate(struct fcrypt *, u_int64_t,
+               struct cryptoini *crie, struct cryptoini *cria, struct csession_info *);
+static int csefree(struct csession *);
+
+static int cryptodev_op(struct csession *, struct crypt_op *);
+static int cryptodev_key(struct crypt_kop *);
+static int cryptodev_find(struct crypt_find_op *);
+
+static int cryptodev_cb(void *);
+static int cryptodev_open(struct inode *inode, struct file *filp);
+
+/*
+ * Check a crypto identifier to see if it requested
+ * a valid crid and it's capabilities match.
+ */
+static int
+checkcrid(int crid)
+{
+       int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
+       int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
+       int caps = 0;
+       
+       /* if the user hasn't selected a driver, then just call newsession */
+       if (hid == 0 && typ != 0)
+               return 0;
+
+       caps = crypto_getcaps(hid);
+
+       /* didn't find anything with capabilities */
+       if (caps == 0) {
+               dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ);
+               return EINVAL;
+       }
+       
+       /* the user didn't specify SW or HW, so the driver is ok */
+       if (typ == 0)
+               return 0;
+
+       /* if the type specified didn't match */
+       if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) {
+               dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__,
+                               hid, typ, caps);
+               return EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+cryptodev_op(struct csession *cse, struct crypt_op *cop)
+{
+       struct cryptop *crp = NULL;
+       struct cryptodesc *crde = NULL, *crda = NULL;
+       int error = 0;
+
+       dprintk("%s()\n", __FUNCTION__);
+       if (cop->len > CRYPTO_MAX_DATA_LEN) {
+               dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN);
+               return (E2BIG);
+       }
+
+       if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) {
+               dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize,
+                               cop->len);
+               return (EINVAL);
+       }
+
+       cse->uio.uio_iov = &cse->iovec;
+       cse->uio.uio_iovcnt = 1;
+       cse->uio.uio_offset = 0;
+#if 0
+       cse->uio.uio_resid = cop->len;
+       cse->uio.uio_segflg = UIO_SYSSPACE;
+       cse->uio.uio_rw = UIO_WRITE;
+       cse->uio.uio_td = td;
+#endif
+       cse->uio.uio_iov[0].iov_len = cop->len;
+       if (cse->info.authsize)
+               cse->uio.uio_iov[0].iov_len += cse->info.authsize;
+       cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len,
+                       GFP_KERNEL);
+
+       if (cse->uio.uio_iov[0].iov_base == NULL) {
+               dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__,
+                               cse->uio.uio_iov[0].iov_len);
+               return (ENOMEM);
+       }
+
+       crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0));
+       if (crp == NULL) {
+               dprintk("%s: ENOMEM\n", __FUNCTION__);
+               error = ENOMEM;
+               goto bail;
+       }
+
+       if (cse->info.authsize) {
+               crda = crp->crp_desc;
+               if (cse->info.blocksize)
+                       crde = crda->crd_next;
+       } else {
+               if (cse->info.blocksize)
+                       crde = crp->crp_desc;
+               else {
+                       dprintk("%s: bad request\n", __FUNCTION__);
+                       error = EINVAL;
+                       goto bail;
+               }
+       }
+
+       if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src,
+                                       cop->len))) {
+               dprintk("%s: bad copy\n", __FUNCTION__);
+               goto bail;
+       }
+
+       if (crda) {
+               crda->crd_skip = 0;
+               crda->crd_len = cop->len;
+               crda->crd_inject = cop->len;
+
+               crda->crd_alg = cse->mac;
+               crda->crd_key = cse->mackey;
+               crda->crd_klen = cse->mackeylen * 8;
+       }
+
+       if (crde) {
+               if (cop->op == COP_ENCRYPT)
+                       crde->crd_flags |= CRD_F_ENCRYPT;
+               else
+                       crde->crd_flags &= ~CRD_F_ENCRYPT;
+               crde->crd_len = cop->len;
+               crde->crd_inject = 0;
+
+               crde->crd_alg = cse->cipher;
+               crde->crd_key = cse->key;
+               crde->crd_klen = cse->keylen * 8;
+       }
+
+       crp->crp_ilen = cse->uio.uio_iov[0].iov_len;
+       crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
+                      | (cop->flags & COP_F_BATCH);
+       crp->crp_buf = (caddr_t)&cse->uio;
+       crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
+       crp->crp_sid = cse->sid;
+       crp->crp_opaque = (void *)cse;
+
+       if (cop->iv) {
+               if (crde == NULL) {
+                       error = EINVAL;
+                       dprintk("%s no crde\n", __FUNCTION__);
+                       goto bail;
+               }
+               if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
+                       error = EINVAL;
+                       dprintk("%s arc4 with IV\n", __FUNCTION__);
+                       goto bail;
+               }
+               if ((error = copy_from_user(cse->tmp_iv, cop->iv,
+                                               cse->info.blocksize))) {
+                       dprintk("%s bad iv copy\n", __FUNCTION__);
+                       goto bail;
+               }
+               memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize);
+               crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
+               crde->crd_skip = 0;
+       } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
+               crde->crd_skip = 0;
+       } else if (crde) {
+               crde->crd_flags |= CRD_F_IV_PRESENT;
+               crde->crd_skip = cse->info.blocksize;
+               crde->crd_len -= cse->info.blocksize;
+       }
+
+       if (cop->mac && crda == NULL) {
+               error = EINVAL;
+               dprintk("%s no crda\n", __FUNCTION__);
+               goto bail;
+       }
+
+       /*
+        * Let the dispatch run unlocked, then, interlock against the
+        * callback before checking if the operation completed and going
+        * to sleep.  This insures drivers don't inherit our lock which
+        * results in a lock order reversal between crypto_dispatch forced
+        * entry and the crypto_done callback into us.
+        */
+       error = crypto_dispatch(crp);
+       if (error == 0) {
+               dprintk("%s about to WAIT\n", __FUNCTION__);
+               /*
+                * we really need to wait for driver to complete to maintain
+                * state,  luckily interrupts will be remembered
+                */
+               do {
+                       error = wait_event_interruptible(crp->crp_waitq,
+                                       ((crp->crp_flags & CRYPTO_F_DONE) != 0));
+                       /*
+                        * we can't break out of this loop or we will leave behind
+                        * a huge mess,  however,  staying here means if your driver
+                        * is broken user applications can hang and not be killed.
+                        * The solution,  fix your driver :-)
+                        */
+                       if (error) {
+                               schedule();
+                               error = 0;
+                       }
+               } while ((crp->crp_flags & CRYPTO_F_DONE) == 0);
+               dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
+       }
+
+       if (crp->crp_etype != 0) {
+               error = crp->crp_etype;
+               dprintk("%s error in crp processing\n", __FUNCTION__);
+               goto bail;
+       }
+
+       if (cse->error) {
+               error = cse->error;
+               dprintk("%s error in cse processing\n", __FUNCTION__);
+               goto bail;
+       }
+
+       if (cop->dst && (error = copy_to_user(cop->dst,
+                                       cse->uio.uio_iov[0].iov_base, cop->len))) {
+               dprintk("%s bad dst copy\n", __FUNCTION__);
+               goto bail;
+       }
+
+       if (cop->mac &&
+                       (error=copy_to_user(cop->mac,
+                               (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
+                               cse->info.authsize))) {
+               dprintk("%s bad mac copy\n", __FUNCTION__);
+               goto bail;
+       }
+
+bail:
+       if (crp)
+               crypto_freereq(crp);
+       if (cse->uio.uio_iov[0].iov_base)
+               kfree(cse->uio.uio_iov[0].iov_base);
+
+       return (error);
+}
+
+static int
+cryptodev_cb(void *op)
+{
+       struct cryptop *crp = (struct cryptop *) op;
+       struct csession *cse = (struct csession *)crp->crp_opaque;
+       int error;
+
+       dprintk("%s()\n", __FUNCTION__);
+       error = crp->crp_etype;
+       if (error == EAGAIN) {
+               crp->crp_flags &= ~CRYPTO_F_DONE;
+#ifdef NOTYET
+               /*
+                * DAVIDM I am fairly sure that we should turn this into a batch
+                * request to stop bad karma/lockup, revisit
+                */
+               crp->crp_flags |= CRYPTO_F_BATCH;
+#endif
+               return crypto_dispatch(crp);
+       }
+       if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
+               cse->error = error;
+               wake_up_interruptible(&crp->crp_waitq);
+       }
+       return (0);
+}
+
+static int
+cryptodevkey_cb(void *op)
+{
+       struct cryptkop *krp = (struct cryptkop *) op;
+       dprintk("%s()\n", __FUNCTION__);
+       wake_up_interruptible(&krp->krp_waitq);
+       return (0);
+}
+
+static int
+cryptodev_key(struct crypt_kop *kop)
+{
+       struct cryptkop *krp = NULL;
+       int error = EINVAL;
+       int in, out, size, i;
+
+       dprintk("%s()\n", __FUNCTION__);
+       if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
+               dprintk("%s params too big\n", __FUNCTION__);
+               return (EFBIG);
+       }
+
+       in = kop->crk_iparams;
+       out = kop->crk_oparams;
+       switch (kop->crk_op) {
+       case CRK_MOD_EXP:
+               if (in == 3 && out == 1)
+                       break;
+               return (EINVAL);
+       case CRK_MOD_EXP_CRT:
+               if (in == 6 && out == 1)
+                       break;
+               return (EINVAL);
+       case CRK_DSA_SIGN:
+               if (in == 5 && out == 2)
+                       break;
+               return (EINVAL);
+       case CRK_DSA_VERIFY:
+               if (in == 7 && out == 0)
+                       break;
+               return (EINVAL);
+       case CRK_DH_COMPUTE_KEY:
+               if (in == 3 && out == 1)
+                       break;
+               return (EINVAL);
+       default:
+               return (EINVAL);
+       }
+
+       krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL);
+       if (!krp)
+               return (ENOMEM);
+       bzero(krp, sizeof *krp);
+       krp->krp_op = kop->crk_op;
+       krp->krp_status = kop->crk_status;
+       krp->krp_iparams = kop->crk_iparams;
+       krp->krp_oparams = kop->crk_oparams;
+       krp->krp_crid = kop->crk_crid;
+       krp->krp_status = 0;
+       krp->krp_flags = CRYPTO_KF_CBIMM;
+       krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
+       init_waitqueue_head(&krp->krp_waitq);
+
+       for (i = 0; i < CRK_MAXPARAM; i++)
+               krp->krp_param[i].crp_nbits = kop->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 = (caddr_t) kmalloc(size, GFP_KERNEL);
+               if (i >= krp->krp_iparams)
+                       continue;
+               error = copy_from_user(krp->krp_param[i].crp_p,
+                               kop->crk_param[i].crp_p, size);
+               if (error)
+                       goto fail;
+       }
+
+       error = crypto_kdispatch(krp);
+       if (error)
+               goto fail;
+
+       do {
+               error = wait_event_interruptible(krp->krp_waitq,
+                               ((krp->krp_flags & CRYPTO_KF_DONE) != 0));
+               /*
+                * we can't break out of this loop or we will leave behind
+                * a huge mess,  however,  staying here means if your driver
+                * is broken user applications can hang and not be killed.
+                * The solution,  fix your driver :-)
+                */
+               if (error) {
+                       schedule();
+                       error = 0;
+               }
+       } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0);
+
+       dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
+       
+       kop->crk_crid = krp->krp_crid;          /* device that did the work */
+       if (krp->krp_status != 0) {
+               error = 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;
+               error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p,
+                               size);
+               if (error)
+                       goto fail;
+       }
+
+fail:
+       if (krp) {
+               kop->crk_status = krp->krp_status;
+               for (i = 0; i < CRK_MAXPARAM; i++) {
+                       if (krp->krp_param[i].crp_p)
+                               kfree(krp->krp_param[i].crp_p);
+               }
+               kfree(krp);
+       }
+       return (error);
+}
+
+static int
+cryptodev_find(struct crypt_find_op *find)
+{
+       device_t dev;
+
+       if (find->crid != -1) {
+               dev = crypto_find_device_byhid(find->crid);
+               if (dev == NULL)
+                       return (ENOENT);
+               strlcpy(find->name, device_get_nameunit(dev),
+                   sizeof(find->name));
+       } else {
+               find->crid = crypto_find_driver(find->name);
+               if (find->crid == -1)
+                       return (ENOENT);
+       }
+       return (0);
+}
+
+static struct csession *
+csefind(struct fcrypt *fcr, u_int ses)
+{
+       struct csession *cse;
+
+       dprintk("%s()\n", __FUNCTION__);
+       list_for_each_entry(cse, &fcr->csessions, list)
+               if (cse->ses == ses)
+                       return (cse);
+       return (NULL);
+}
+
+static int
+csedelete(struct fcrypt *fcr, struct csession *cse_del)
+{
+       struct csession *cse;
+
+       dprintk("%s()\n", __FUNCTION__);
+       list_for_each_entry(cse, &fcr->csessions, list) {
+               if (cse == cse_del) {
+                       list_del(&cse->list);
+                       return (1);
+               }
+       }
+       return (0);
+}
+       
+static struct csession *
+cseadd(struct fcrypt *fcr, struct csession *cse)
+{
+       dprintk("%s()\n", __FUNCTION__);
+       list_add_tail(&cse->list, &fcr->csessions);
+       cse->ses = fcr->sesn++;
+       return (cse);
+}
+
+static struct csession *
+csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie,
+       struct cryptoini *cria, struct csession_info *info)
+{
+       struct csession *cse;
+
+       dprintk("%s()\n", __FUNCTION__);
+       cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL);
+       if (cse == NULL)
+               return NULL;
+       memset(cse, 0, sizeof(struct csession));
+
+       INIT_LIST_HEAD(&cse->list);
+       init_waitqueue_head(&cse->waitq);
+
+       cse->key = crie->cri_key;
+       cse->keylen = crie->cri_klen/8;
+       cse->mackey = cria->cri_key;
+       cse->mackeylen = cria->cri_klen/8;
+       cse->sid = sid;
+       cse->cipher = crie->cri_alg;
+       cse->mac = cria->cri_alg;
+       cse->info = *info;
+       cseadd(fcr, cse);
+       return (cse);
+}
+
+static int
+csefree(struct csession *cse)
+{
+       int error;
+
+       dprintk("%s()\n", __FUNCTION__);
+       error = crypto_freesession(cse->sid);
+       if (cse->key)
+               kfree(cse->key);
+       if (cse->mackey)
+               kfree(cse->mackey);
+       kfree(cse);
+       return(error);
+}
+
+static int
+cryptodev_ioctl(
+       struct inode *inode,
+       struct file *filp,
+       unsigned int cmd,
+       unsigned long arg)
+{
+       struct cryptoini cria, crie;
+       struct fcrypt *fcr = filp->private_data;
+       struct csession *cse;
+       struct csession_info info;
+       struct session2_op sop;
+       struct crypt_op cop;
+       struct crypt_kop kop;
+       struct crypt_find_op fop;
+       u_int64_t sid;
+       u_int32_t ses;
+       int feat, fd, error = 0, crid;
+       mm_segment_t fs;
+
+       dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg);
+
+       switch (cmd) {
+
+       case CRIOGET: {
+               dprintk("%s(CRIOGET)\n", __FUNCTION__);
+               fs = get_fs();
+               set_fs(get_ds());
+               for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
+                       if (files_fdtable(current->files)->fd[fd] == filp)
+                               break;
+               fd = sys_dup(fd);
+               set_fs(fs);
+               put_user(fd, (int *) arg);
+               return IS_ERR_VALUE(fd) ? fd : 0;
+               }
+
+#define        CIOCGSESSSTR    (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2")
+       case CIOCGSESSION:
+       case CIOCGSESSION2:
+               dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR);
+               memset(&crie, 0, sizeof(crie));
+               memset(&cria, 0, sizeof(cria));
+               memset(&info, 0, sizeof(info));
+               memset(&sop, 0, sizeof(sop));
+
+               if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ?
+                                       sizeof(struct session_op) : sizeof(sop))) {
+                       dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+                       error = EFAULT;
+                       goto bail;
+               }
+
+               switch (sop.cipher) {
+               case 0:
+                       dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR);
+                       break;
+               case CRYPTO_NULL_CBC:
+                       info.blocksize = NULL_BLOCK_LEN;
+                       info.minkey = NULL_MIN_KEY_LEN;
+                       info.maxkey = NULL_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_DES_CBC:
+                       info.blocksize = DES_BLOCK_LEN;
+                       info.minkey = DES_MIN_KEY_LEN;
+                       info.maxkey = DES_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_3DES_CBC:
+                       info.blocksize = DES3_BLOCK_LEN;
+                       info.minkey = DES3_MIN_KEY_LEN;
+                       info.maxkey = DES3_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_BLF_CBC:
+                       info.blocksize = BLOWFISH_BLOCK_LEN;
+                       info.minkey = BLOWFISH_MIN_KEY_LEN;
+                       info.maxkey = BLOWFISH_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_CAST_CBC:
+                       info.blocksize = CAST128_BLOCK_LEN;
+                       info.minkey = CAST128_MIN_KEY_LEN;
+                       info.maxkey = CAST128_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_SKIPJACK_CBC:
+                       info.blocksize = SKIPJACK_BLOCK_LEN;
+                       info.minkey = SKIPJACK_MIN_KEY_LEN;
+                       info.maxkey = SKIPJACK_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_AES_CBC:
+                       info.blocksize = AES_BLOCK_LEN;
+                       info.minkey = AES_MIN_KEY_LEN;
+                       info.maxkey = AES_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_ARC4:
+                       info.blocksize = ARC4_BLOCK_LEN;
+                       info.minkey = ARC4_MIN_KEY_LEN;
+                       info.maxkey = ARC4_MAX_KEY_LEN;
+                       break;
+               case CRYPTO_CAMELLIA_CBC:
+                       info.blocksize = CAMELLIA_BLOCK_LEN;
+                       info.minkey = CAMELLIA_MIN_KEY_LEN;
+                       info.maxkey = CAMELLIA_MAX_KEY_LEN;
+                       break;
+               default:
+                       dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR);
+                       error = EINVAL;
+                       goto bail;
+               }
+
+               switch (sop.mac) {
+               case 0:
+                       dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR);
+                       break;
+               case CRYPTO_NULL_HMAC:
+                       info.authsize = NULL_HASH_LEN;
+                       break;
+               case CRYPTO_MD5:
+                       info.authsize = MD5_HASH_LEN;
+                       break;
+               case CRYPTO_SHA1:
+                       info.authsize = SHA1_HASH_LEN;
+                       break;
+               case CRYPTO_SHA2_256:
+                       info.authsize = SHA2_256_HASH_LEN;
+                       break;
+               case CRYPTO_SHA2_384:
+                       info.authsize = SHA2_384_HASH_LEN;
+                       break;
+               case CRYPTO_SHA2_512:
+                       info.authsize = SHA2_512_HASH_LEN;
+                       break;
+               case CRYPTO_RIPEMD160:
+                       info.authsize = RIPEMD160_HASH_LEN;
+                       break;
+               case CRYPTO_MD5_HMAC:
+                       info.authsize = MD5_HASH_LEN;
+                       break;
+               case CRYPTO_SHA1_HMAC:
+                       info.authsize = SHA1_HASH_LEN;
+                       break;
+               case CRYPTO_SHA2_256_HMAC:
+                       info.authsize = SHA2_256_HASH_LEN;
+                       break;
+               case CRYPTO_SHA2_384_HMAC:
+                       info.authsize = SHA2_384_HASH_LEN;
+                       break;
+               case CRYPTO_SHA2_512_HMAC:
+                       info.authsize = SHA2_512_HASH_LEN;
+                       break;
+               case CRYPTO_RIPEMD160_HMAC:
+                       info.authsize = RIPEMD160_HASH_LEN;
+                       break;
+               default:
+                       dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR);
+                       error = EINVAL;
+                       goto bail;
+               }
+
+               if (info.blocksize) {
+                       crie.cri_alg = sop.cipher;
+                       crie.cri_klen = sop.keylen * 8;
+                       if ((info.maxkey && sop.keylen > info.maxkey) ||
+                                       sop.keylen < info.minkey) {
+                               dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR);
+                               error = EINVAL;
+                               goto bail;
+                       }
+
+                       crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL);
+                       if (copy_from_user(crie.cri_key, sop.key,
+                                                       crie.cri_klen/8)) {
+                               dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+                               error = EFAULT;
+                               goto bail;
+                       }
+                       if (info.authsize)
+                               crie.cri_next = &cria;
+               }
+
+               if (info.authsize) {
+                       cria.cri_alg = sop.mac;
+                       cria.cri_klen = sop.mackeylen * 8;
+                       if ((info.maxkey && sop.mackeylen > info.maxkey) ||
+                                       sop.keylen < info.minkey) {
+                               dprintk("%s(%s) - mackeylen %d\n", __FUNCTION__, CIOCGSESSSTR,
+                                               sop.mackeylen);
+                               error = EINVAL;
+                               goto bail;
+                       }
+
+                       if (cria.cri_klen) {
+                               cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL);
+                               if (copy_from_user(cria.cri_key, sop.mackey,
+                                                               cria.cri_klen / 8)) {
+                                       dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+                                       error = EFAULT;
+                                       goto bail;
+                               }
+                       }
+               }
+
+               /* NB: CIOGSESSION2 has the crid */
+               if (cmd == CIOCGSESSION2) {
+                       crid = sop.crid;
+                       error = checkcrid(crid);
+                       if (error) {
+                               dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__,
+                                               CIOCGSESSSTR, error);
+                               goto bail;
+                       }
+               } else {
+                       /* allow either HW or SW to be used */
+                       crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
+               }
+               error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid);
+               if (error) {
+                       dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error);
+                       goto bail;
+               }
+
+               cse = csecreate(fcr, sid, &crie, &cria, &info);
+               if (cse == NULL) {
+                       crypto_freesession(sid);
+                       error = EINVAL;
+                       dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR);
+                       goto bail;
+               }
+               sop.ses = cse->ses;
+
+               if (cmd == CIOCGSESSION2) {
+                       /* return hardware/driver id */
+                       sop.crid = CRYPTO_SESID2HID(cse->sid);
+               }
+
+               if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ?
+                                       sizeof(struct session_op) : sizeof(sop))) {
+                       dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
+                       error = EFAULT;
+               }
+bail:
+               if (error) {
+                       dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error);
+                       if (crie.cri_key)
+                               kfree(crie.cri_key);
+                       if (cria.cri_key)
+                               kfree(cria.cri_key);
+               }
+               break;
+       case CIOCFSESSION:
+               dprintk("%s(CIOCFSESSION)\n", __FUNCTION__);
+               get_user(ses, (uint32_t*)arg);
+               cse = csefind(fcr, ses);
+               if (cse == NULL) {
+                       error = EINVAL;
+                       dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error);
+                       break;
+               }
+               csedelete(fcr, cse);
+               error = csefree(cse);
+               break;
+       case CIOCCRYPT:
+               dprintk("%s(CIOCCRYPT)\n", __FUNCTION__);
+               if(copy_from_user(&cop, (void*)arg, sizeof(cop))) {
+                       dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__);
+                       error = EFAULT;
+                       goto bail;
+               }
+               cse = csefind(fcr, cop.ses);
+               if (cse == NULL) {
+                       error = EINVAL;
+                       dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error);
+                       break;
+               }
+               error = cryptodev_op(cse, &cop);
+               if(copy_to_user((void*)arg, &cop, sizeof(cop))) {
+                       dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__);
+                       error = EFAULT;
+                       goto bail;
+               }
+               break;
+       case CIOCKEY:
+       case CIOCKEY2:
+               dprintk("%s(CIOCKEY)\n", __FUNCTION__);
+               if (!crypto_userasymcrypto)
+                       return (EPERM);         /* XXX compat? */
+               if(copy_from_user(&kop, (void*)arg, sizeof(kop))) {
+                       dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__);
+                       error = EFAULT;
+                       goto bail;
+               }
+               if (cmd == CIOCKEY) {
+                       /* NB: crypto core enforces s/w driver use */
+                       kop.crk_crid =
+                           CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
+               }
+               error = cryptodev_key(&kop);
+               if(copy_to_user((void*)arg, &kop, sizeof(kop))) {
+                       dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__);
+                       error = EFAULT;
+                       goto bail;
+               }
+               break;
+       case CIOCASYMFEAT:
+               dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__);
+               if (!crypto_userasymcrypto) {
+                       /*
+                        * NB: if user asym crypto operations are
+                        * not permitted return "no algorithms"
+                        * so well-behaved applications will just
+                        * fallback to doing them in software.
+                        */
+                       feat = 0;
+               } else
+                       error = crypto_getfeat(&feat);
+               if (!error) {
+                 error = copy_to_user((void*)arg, &feat, sizeof(feat));
+               }
+               break;
+       case CIOCFINDDEV:
+               if (copy_from_user(&fop, (void*)arg, sizeof(fop))) {
+                       dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__);
+                       error = EFAULT;
+                       goto bail;
+               }
+               error = cryptodev_find(&fop);
+               if (copy_to_user((void*)arg, &fop, sizeof(fop))) {
+                       dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__);
+                       error = EFAULT;
+                       goto bail;
+               }
+               break;
+       default:
+               dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd);
+               error = EINVAL;
+               break;
+       }
+       return(-error);
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+static long
+cryptodev_unlocked_ioctl(
+       struct file *filp,
+       unsigned int cmd,
+       unsigned long arg)
+{
+       return cryptodev_ioctl(NULL, filp, cmd, arg);
+}
+#endif
+
+static int
+cryptodev_open(struct inode *inode, struct file *filp)
+{
+       struct fcrypt *fcr;
+
+       dprintk("%s()\n", __FUNCTION__);
+       if (filp->private_data) {
+               printk("cryptodev: Private data already exists !\n");
+               return(0);
+       }
+
+       fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
+       if (!fcr) {
+               dprintk("%s() - malloc failed\n", __FUNCTION__);
+               return(-ENOMEM);
+       }
+       memset(fcr, 0, sizeof(*fcr));
+
+       INIT_LIST_HEAD(&fcr->csessions);
+       filp->private_data = fcr;
+       return(0);
+}
+
+static int
+cryptodev_release(struct inode *inode, struct file *filp)
+{
+       struct fcrypt *fcr = filp->private_data;
+       struct csession *cse, *tmp;
+
+       dprintk("%s()\n", __FUNCTION__);
+       if (!filp) {
+               printk("cryptodev: No private data on release\n");
+               return(0);
+       }
+
+       list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) {
+               list_del(&cse->list);
+               (void)csefree(cse);
+       }
+       filp->private_data = NULL;
+       kfree(fcr);
+       return(0);
+}
+
+static struct file_operations cryptodev_fops = {
+       .owner = THIS_MODULE,
+       .open = cryptodev_open,
+       .release = cryptodev_release,
+       .ioctl = cryptodev_ioctl,
+#ifdef HAVE_UNLOCKED_IOCTL
+       .unlocked_ioctl = cryptodev_unlocked_ioctl,
+#endif
+};
+
+static struct miscdevice cryptodev = {
+       .minor = CRYPTODEV_MINOR,
+       .name = "crypto",
+       .fops = &cryptodev_fops,
+};
+
+static int __init
+cryptodev_init(void)
+{
+       int rc;
+
+       dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init);
+       rc = misc_register(&cryptodev);
+       if (rc) {
+               printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n");
+               return(rc);
+       }
+
+       return(0);
+}
+
+static void __exit
+cryptodev_exit(void)
+{
+       dprintk("%s()\n", __FUNCTION__);
+       misc_deregister(&cryptodev);
+}
+
+module_init(cryptodev_init);
+module_exit(cryptodev_exit);
+
+MODULE_LICENSE("BSD");
+MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
+MODULE_DESCRIPTION("Cryptodev (user interface to OCF)");
diff --git a/target/linux/generic-2.6/files/crypto/ocf/cryptodev.h b/target/linux/generic-2.6/files/crypto/ocf/cryptodev.h
new file mode 100644 (file)
index 0000000..fa1a57b
--- /dev/null
@@ -0,0 +1,478 @@
+/*     $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $   */
+/*     $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $     */
+
+/*-
+ * Linux port done by David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2006-2007 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ * The license and original author are listed below.
+ *
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Copyright (c) 2001 Theo de Raadt
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+ */
+
+#ifndef _CRYPTO_CRYPTO_H_
+#define _CRYPTO_CRYPTO_H_
+
+/* Some initial values */
+#define CRYPTO_DRIVERS_INITIAL 4
+#define CRYPTO_SW_SESSIONS     32
+
+/* Hash values */
+#define NULL_HASH_LEN          0
+#define MD5_HASH_LEN           16
+#define SHA1_HASH_LEN          20
+#define RIPEMD160_HASH_LEN     20
+#define SHA2_256_HASH_LEN      32
+#define SHA2_384_HASH_LEN      48
+#define SHA2_512_HASH_LEN      64
+#define MD5_KPDK_HASH_LEN      16
+#define SHA1_KPDK_HASH_LEN     20
+/* Maximum hash algorithm result length */
+#define HASH_MAX_LEN           SHA2_512_HASH_LEN /* Keep this updated */
+
+/* HMAC values */
+#define NULL_HMAC_BLOCK_LEN                    1
+#define MD5_HMAC_BLOCK_LEN                     64
+#define SHA1_HMAC_BLOCK_LEN                    64
+#define RIPEMD160_HMAC_BLOCK_LEN       64
+#define SHA2_256_HMAC_BLOCK_LEN                64
+#define SHA2_384_HMAC_BLOCK_LEN                128
+#define SHA2_512_HMAC_BLOCK_LEN                128
+/* Maximum HMAC block length */
+#define HMAC_MAX_BLOCK_LEN             SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */
+#define HMAC_IPAD_VAL                  0x36
+#define HMAC_OPAD_VAL                  0x5C
+
+/* Encryption algorithm block sizes */
+#define NULL_BLOCK_LEN                 1
+#define DES_BLOCK_LEN                  8
+#define DES3_BLOCK_LEN                 8
+#define BLOWFISH_BLOCK_LEN             8
+#define SKIPJACK_BLOCK_LEN             8
+#define CAST128_BLOCK_LEN              8
+#define RIJNDAEL128_BLOCK_LEN  16
+#define AES_BLOCK_LEN                  RIJNDAEL128_BLOCK_LEN
+#define CAMELLIA_BLOCK_LEN             16
+#define ARC4_BLOCK_LEN                 1
+#define EALG_MAX_BLOCK_LEN             AES_BLOCK_LEN /* Keep this updated */
+
+/* Encryption algorithm min and max key sizes */
+#define NULL_MIN_KEY_LEN               0
+#define NULL_MAX_KEY_LEN               0
+#define DES_MIN_KEY_LEN                        8
+#define DES_MAX_KEY_LEN                        8
+#define DES3_MIN_KEY_LEN               24
+#define DES3_MAX_KEY_LEN               24
+#define BLOWFISH_MIN_KEY_LEN   4
+#define BLOWFISH_MAX_KEY_LEN   56
+#define SKIPJACK_MIN_KEY_LEN   10
+#define SKIPJACK_MAX_KEY_LEN   10
+#define CAST128_MIN_KEY_LEN            5
+#define CAST128_MAX_KEY_LEN            16
+#define RIJNDAEL128_MIN_KEY_LEN        16
+#define RIJNDAEL128_MAX_KEY_LEN        32
+#define AES_MIN_KEY_LEN                        RIJNDAEL128_MIN_KEY_LEN
+#define AES_MAX_KEY_LEN                        RIJNDAEL128_MAX_KEY_LEN
+#define CAMELLIA_MIN_KEY_LEN   16
+#define CAMELLIA_MAX_KEY_LEN   32
+#define ARC4_MIN_KEY_LEN               1
+#define ARC4_MAX_KEY_LEN               256
+
+/* Max size of data that can be processed */
+#define CRYPTO_MAX_DATA_LEN            64*1024 - 1
+
+#define CRYPTO_ALGORITHM_MIN   1
+#define CRYPTO_DES_CBC                 1
+#define CRYPTO_3DES_CBC                        2
+#define CRYPTO_BLF_CBC                 3
+#define CRYPTO_CAST_CBC                        4
+#define CRYPTO_SKIPJACK_CBC            5
+#define CRYPTO_MD5_HMAC                        6
+#define CRYPTO_SHA1_HMAC               7
+#define CRYPTO_RIPEMD160_HMAC  8
+#define CRYPTO_MD5_KPDK                        9
+#define CRYPTO_SHA1_KPDK               10
+#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */
+#define CRYPTO_AES_CBC                 11 /* 128 bit blocksize -- the same as above */
+#define CRYPTO_ARC4                            12
+#define CRYPTO_MD5                             13
+#define CRYPTO_SHA1                            14
+#define CRYPTO_NULL_HMAC               15
+#define CRYPTO_NULL_CBC                        16
+#define CRYPTO_DEFLATE_COMP            17 /* Deflate compression algorithm */
+#define CRYPTO_SHA2_256_HMAC   18
+#define CRYPTO_SHA2_384_HMAC   19
+#define CRYPTO_SHA2_512_HMAC   20
+#define CRYPTO_CAMELLIA_CBC            21
+#define CRYPTO_SHA2_256                        22
+#define CRYPTO_SHA2_384                        23
+#define CRYPTO_SHA2_512                        24
+#define CRYPTO_RIPEMD160               25
+#define CRYPTO_ALGORITHM_MAX   25 /* Keep updated - see below */
+
+/* Algorithm flags */
+#define CRYPTO_ALG_FLAG_SUPPORTED      0x01 /* Algorithm is supported */
+#define CRYPTO_ALG_FLAG_RNG_ENABLE     0x02 /* Has HW RNG for DH/DSA */
+#define CRYPTO_ALG_FLAG_DSA_SHA                0x04 /* Can do SHA on msg */
+
+/*
+ * Crypto driver/device flags.  They can set in the crid
+ * parameter when creating a session or submitting a key
+ * op to affect the device/driver assigned.  If neither
+ * of these are specified then the crid is assumed to hold
+ * the driver id of an existing (and suitable) device that
+ * must be used to satisfy the request.
+ */
+#define CRYPTO_FLAG_HARDWARE   0x01000000      /* hardware accelerated */
+#define CRYPTO_FLAG_SOFTWARE   0x02000000      /* software implementation */
+
+/* NB: deprecated */
+struct session_op {
+       u_int32_t       cipher;         /* ie. CRYPTO_DES_CBC */
+       u_int32_t       mac;            /* ie. CRYPTO_MD5_HMAC */
+
+       u_int32_t       keylen;         /* cipher key */
+       caddr_t         key;
+       int             mackeylen;      /* mac key */
+       caddr_t         mackey;
+
+       u_int32_t       ses;            /* returns: session # */ 
+};
+
+struct session2_op {
+       u_int32_t       cipher;         /* ie. CRYPTO_DES_CBC */
+       u_int32_t       mac;            /* ie. CRYPTO_MD5_HMAC */
+
+       u_int32_t       keylen;         /* cipher key */
+       caddr_t         key;
+       int             mackeylen;      /* mac key */
+       caddr_t         mackey;
+
+       u_int32_t       ses;            /* returns: session # */ 
+       int             crid;           /* driver id + flags (rw) */
+       int             pad[4];         /* for future expansion */
+};
+
+struct crypt_op {
+       u_int32_t       ses;
+       u_int16_t       op;             /* i.e. COP_ENCRYPT */
+#define COP_NONE       0
+#define COP_ENCRYPT    1
+#define COP_DECRYPT    2
+       u_int16_t       flags;
+#define        COP_F_BATCH     0x0008          /* Batch op if possible */
+       u_int           len;
+       caddr_t         src, dst;       /* become iov[] inside kernel */
+       caddr_t         mac;            /* must be big enough for chosen MAC */
+       caddr_t         iv;
+};
+
+/*
+ * Parameters for looking up a crypto driver/device by
+ * device name or by id.  The latter are returned for
+ * created sessions (crid) and completed key operations.
+ */
+struct crypt_find_op {
+       int             crid;           /* driver id + flags */
+       char            name[32];       /* device/driver name */
+};
+
+/* bignum parameter, in packed bytes, ... */
+struct crparam {
+       caddr_t         crp_p;
+       u_int           crp_nbits;
+};
+
+#define CRK_MAXPARAM   8
+
+struct crypt_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_crid;       /* NB: only used by CIOCKEY2 (rw) */
+       struct crparam  crk_param[CRK_MAXPARAM];
+};
+#define CRK_ALGORITM_MIN       0
+#define CRK_MOD_EXP            0
+#define CRK_MOD_EXP_CRT                1
+#define CRK_DSA_SIGN           2
+#define CRK_DSA_VERIFY         3
+#define CRK_DH_COMPUTE_KEY     4
+#define CRK_ALGORITHM_MAX      4 /* Keep updated - see below */
+
+#define CRF_MOD_EXP            (1 << CRK_MOD_EXP)
+#define CRF_MOD_EXP_CRT                (1 << CRK_MOD_EXP_CRT)
+#define CRF_DSA_SIGN           (1 << CRK_DSA_SIGN)
+#define CRF_DSA_VERIFY         (1 << CRK_DSA_VERIFY)
+#define CRF_DH_COMPUTE_KEY     (1 << CRK_DH_COMPUTE_KEY)
+
+/*
+ * done against open of /dev/crypto, to get a cloned descriptor.
+ * Please use F_SETFD against the cloned descriptor.
+ */
+#define CRIOGET                _IOWR('c', 100, u_int32_t)
+#define CRIOASYMFEAT   CIOCASYMFEAT
+#define CRIOFINDDEV    CIOCFINDDEV
+
+/* the following are done against the cloned descriptor */
+#define CIOCGSESSION   _IOWR('c', 101, struct session_op)
+#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 CIOCASYMFEAT   _IOR('c', 105, u_int32_t)
+#define CIOCGSESSION2  _IOWR('c', 106, struct session2_op)
+#define CIOCKEY2       _IOWR('c', 107, struct crypt_kop)
+#define CIOCFINDDEV    _IOWR('c', 108, struct crypt_find_op)
+
+struct cryptotstat {
+       struct timespec acc;            /* total accumulated time */
+       struct timespec min;            /* min time */
+       struct timespec max;            /* max time */
+       u_int32_t       count;          /* number of observations */
+};
+
+struct cryptostats {
+       u_int32_t       cs_ops;         /* symmetric crypto ops submitted */
+       u_int32_t       cs_errs;        /* symmetric crypto ops that failed */
+       u_int32_t       cs_kops;        /* asymetric/key ops submitted */
+       u_int32_t       cs_kerrs;       /* asymetric/key ops that failed */
+       u_int32_t       cs_intrs;       /* crypto swi thread activations */
+       u_int32_t       cs_rets;        /* crypto return thread activations */
+       u_int32_t       cs_blocks;      /* symmetric op driver block */
+       u_int32_t       cs_kblocks;     /* symmetric op driver block */
+       /*
+        * When CRYPTO_TIMING is defined at compile time and the
+        * sysctl debug.crypto is set to 1, the crypto system will
+        * accumulate statistics about how long it takes to process
+        * crypto requests at various points during processing.
+        */
+       struct cryptotstat cs_invoke;   /* crypto_dipsatch -> crypto_invoke */
+       struct cryptotstat cs_done;     /* crypto_invoke -> crypto_done */
+       struct cryptotstat cs_cb;       /* crypto_done -> callback */
+       struct cryptotstat cs_finis;    /* callback -> callback return */
+
+       u_int32_t       cs_drops;               /* crypto ops dropped due to congestion */
+};
+
+#ifdef __KERNEL__
+
+/* Standard initialization structure beginning */
+struct cryptoini {
+       int             cri_alg;        /* Algorithm to use */
+       int             cri_klen;       /* Key length, in bits */
+       int             cri_mlen;       /* Number of bytes we want from the
+                                          entire hash. 0 means all. */
+       caddr_t         cri_key;        /* key to use */
+       u_int8_t        cri_iv[EALG_MAX_BLOCK_LEN];     /* IV to use */
+       struct cryptoini *cri_next;
+};
+
+/* Describe boundaries of a single crypto operation */
+struct cryptodesc {
+       int             crd_skip;       /* How many bytes to ignore from start */
+       int             crd_len;        /* How many bytes to process */
+       int             crd_inject;     /* Where to inject results, if applicable */
+       int             crd_flags;
+
+#define CRD_F_ENCRYPT          0x01    /* Set when doing encryption */
+#define CRD_F_IV_PRESENT       0x02    /* When encrypting, IV is already in
+                                          place, so don't copy. */
+#define CRD_F_IV_EXPLICIT      0x04    /* IV explicitly provided */
+#define CRD_F_DSA_SHA_NEEDED   0x08    /* Compute SHA-1 of buffer for DSA */
+#define CRD_F_KEY_EXPLICIT     0x10    /* Key explicitly provided */
+#define CRD_F_COMP             0x0f    /* Set when doing compression */
+
+       struct cryptoini        CRD_INI; /* Initialization/context data */
+#define crd_iv         CRD_INI.cri_iv
+#define crd_key                CRD_INI.cri_key
+#define crd_alg                CRD_INI.cri_alg
+#define crd_klen       CRD_INI.cri_klen
+
+       struct cryptodesc *crd_next;
+};
+
+/* Structure describing complete operation */
+struct cryptop {
+       struct list_head crp_next;
+       wait_queue_head_t crp_waitq;
+
+       u_int64_t       crp_sid;        /* Session ID */
+       int             crp_ilen;       /* Input data total length */
+       int             crp_olen;       /* Result total length */
+
+       int             crp_etype;      /*
+                                        * Error type (zero means no error).
+                                        * All error codes except EAGAIN
+                                        * indicate possible data corruption (as in,
+                                        * the data have been touched). On all
+                                        * errors, the crp_sid may have changed
+                                        * (reset to a new one), so the caller
+                                        * should always check and use the new
+                                        * value on future requests.
+                                        */
+       int             crp_flags;
+
+#define CRYPTO_F_SKBUF         0x0001  /* Input/output are skbuf chains */
+#define CRYPTO_F_IOV           0x0002  /* Input/output are uio */
+#define CRYPTO_F_REL           0x0004  /* Must return data in same place */
+#define CRYPTO_F_BATCH         0x0008  /* Batch op if possible */
+#define CRYPTO_F_CBIMM         0x0010  /* Do callback immediately */
+#define CRYPTO_F_DONE          0x0020  /* Operation completed */
+#define CRYPTO_F_CBIFSYNC      0x0040  /* Do CBIMM if op is synchronous */
+
+       caddr_t         crp_buf;        /* Data to be processed */
+       caddr_t         crp_opaque;     /* Opaque pointer, passed along */
+       struct cryptodesc *crp_desc;    /* Linked list of processing descriptors */
+
+       int (*crp_callback)(struct cryptop *); /* Callback function */
+};
+
+#define CRYPTO_BUF_CONTIG      0x0
+#define CRYPTO_BUF_IOV         0x1
+#define CRYPTO_BUF_SKBUF               0x2
+
+#define CRYPTO_OP_DECRYPT      0x0
+#define CRYPTO_OP_ENCRYPT      0x1
+
+/*
+ * Hints passed to process methods.
+ */
+#define CRYPTO_HINT_MORE       0x1     /* more ops coming shortly */
+
+struct cryptkop {
+       struct list_head krp_next;
+       wait_queue_head_t krp_waitq;
+
+       int             krp_flags;
+#define CRYPTO_KF_DONE         0x0001  /* Operation completed */
+#define CRYPTO_KF_CBIMM                0x0002  /* Do callback immediately */
+
+       u_int           krp_op;         /* ie. CRK_MOD_EXP or other */
+       u_int           krp_status;     /* return status */
+       u_short         krp_iparams;    /* # of input parameters */
+       u_short         krp_oparams;    /* # of output parameters */
+       u_int           krp_crid;       /* desired device, etc. */
+       u_int32_t       krp_hid;
+       struct crparam  krp_param[CRK_MAXPARAM];        /* kvm */
+       int             (*krp_callback)(struct cryptkop *);
+};
+
+#include <ocf-compat.h>
+
+/*
+ * Session ids are 64 bits.  The lower 32 bits contain a "local id" which
+ * is a driver-private session identifier.  The upper 32 bits contain a
+ * "hardware id" used by the core crypto code to identify the driver and
+ * a copy of the driver's capabilities that can be used by client code to
+ * optimize operation.
+ */
+#define CRYPTO_SESID2HID(_sid) (((_sid) >> 32) & 0x00ffffff)
+#define CRYPTO_SESID2CAPS(_sid)        (((_sid) >> 32) & 0xff000000)
+#define CRYPTO_SESID2LID(_sid) (((u_int32_t) (_sid)) & 0xffffffff)
+
+extern int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard);
+extern int crypto_freesession(u_int64_t sid);
+#define CRYPTOCAP_F_HARDWARE   CRYPTO_FLAG_HARDWARE
+#define CRYPTOCAP_F_SOFTWARE   CRYPTO_FLAG_SOFTWARE
+#define CRYPTOCAP_F_SYNC       0x04000000      /* operates synchronously */
+extern int32_t crypto_get_driverid(device_t dev, int flags);
+extern int crypto_find_driver(const char *);
+extern device_t crypto_find_device_byhid(int hid);
+extern int crypto_getcaps(int hid);
+extern int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
+           u_int32_t flags);
+extern int crypto_kregister(u_int32_t, int, u_int32_t);
+extern int crypto_unregister(u_int32_t driverid, int alg);
+extern int crypto_unregister_all(u_int32_t driverid);
+extern int crypto_dispatch(struct cryptop *crp);
+extern int crypto_kdispatch(struct cryptkop *);
+#define CRYPTO_SYMQ    0x1
+#define CRYPTO_ASYMQ   0x2
+extern int crypto_unblock(u_int32_t, int);
+extern void crypto_done(struct cryptop *crp);
+extern void crypto_kdone(struct cryptkop *);
+extern int crypto_getfeat(int *);
+
+extern void crypto_freereq(struct cryptop *crp);
+extern struct cryptop *crypto_getreq(int num);
+
+extern  int crypto_usercrypto;      /* userland may do crypto requests */
+extern  int crypto_userasymcrypto;  /* userland may do asym crypto reqs */
+extern  int crypto_devallowsoft;    /* only use hardware crypto */
+
+/*
+ * random number support,  crypto_unregister_all will unregister
+ */
+extern int crypto_rregister(u_int32_t driverid,
+               int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg);
+extern int crypto_runregister_all(u_int32_t driverid);
+
+/*
+ * Crypto-related utility routines used mainly by drivers.
+ *
+ * XXX these don't really belong here; but for now they're
+ *     kept apart from the rest of the system.
+ */
+struct uio;
+extern void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp);
+extern void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp);
+extern struct iovec *cuio_getptr(struct uio *uio, int loc, int *off);
+
+extern void crypto_copyback(int flags, caddr_t buf, int off, int size,
+           caddr_t in);
+extern void crypto_copydata(int flags, caddr_t buf, int off, int size,
+           caddr_t out);
+extern int crypto_apply(int flags, caddr_t buf, int off, int len,
+           int (*f)(void *, void *, u_int), void *arg);
+
+#endif /* __KERNEL__ */
+#endif /* _CRYPTO_CRYPTO_H_ */
diff --git a/target/linux/generic-2.6/files/crypto/ocf/cryptosoft.c b/target/linux/generic-2.6/files/crypto/ocf/cryptosoft.c
new file mode 100644 (file)
index 0000000..1486889
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * An OCF module that uses the linux kernel cryptoapi, based on the
+ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu)
+ * but is mostly unrecognisable,
+ *
+ * Written by David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2004-2007 David McCullough
+ * Copyright (C) 2004-2005 Intel Corporation.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <asm/scatterlist.h>
+
+#include <cryptodev.h>
+#include <uio.h>
+
+struct {
+       softc_device_decl       sc_dev;
+} swcr_softc;
+
+#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
+
+/* Software session entry */
+
+#define SW_TYPE_CIPHER         0
+#define SW_TYPE_HMAC           1
+#define SW_TYPE_AUTH2          2
+#define SW_TYPE_HASH           3
+#define SW_TYPE_COMP           4
+#define SW_TYPE_BLKCIPHER      5
+
+struct swcr_data {
+       int                                     sw_type;
+       int                                     sw_alg;
+       struct crypto_tfm       *sw_tfm;
+       union {
+               struct {
+                       char *sw_key;
+                       int  sw_klen;
+                       int  sw_mlen;
+               } hmac;
+               void *sw_comp_buf;
+       } u;
+       struct swcr_data        *sw_next;
+};
+
+#ifndef CRYPTO_TFM_MODE_CBC
+/*
+ * As of linux-2.6.21 this is no longer defined, and presumably no longer
+ * needed to be passed into the crypto core code.
+ */
+#define        CRYPTO_TFM_MODE_CBC     0
+#define        CRYPTO_TFM_MODE_ECB     0
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+       /*
+        * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
+        * API into old API.
+        */
+
+       /* Symmetric/Block Cipher */
+       struct blkcipher_desc
+       {
+               struct crypto_tfm *tfm;
+               void *info;
+       };
+       #define ecb(X)                                                          #X
+       #define cbc(X)                                                          #X
+       #define crypto_has_blkcipher(X, Y, Z)           crypto_alg_available(X, 0)
+       #define crypto_blkcipher_cast(X)                        X
+       #define crypto_blkcipher_tfm(X)                         X
+       #define crypto_alloc_blkcipher(X, Y, Z)         crypto_alloc_tfm(X, mode)
+       #define crypto_blkcipher_ivsize(X)                      crypto_tfm_alg_ivsize(X)
+       #define crypto_blkcipher_blocksize(X)           crypto_tfm_alg_blocksize(X)
+       #define crypto_blkcipher_setkey(X, Y, Z)        crypto_cipher_setkey(X, Y, Z)
+       #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \
+                               crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
+       #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \
+                               crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
+
+       /* Hash/HMAC/Digest */
+       struct hash_desc
+       {
+               struct crypto_tfm *tfm;
+       };
+       #define hmac(X)                                                 #X
+       #define crypto_has_hash(X, Y, Z)                crypto_alg_available(X, 0)
+       #define crypto_hash_cast(X)                             X
+       #define crypto_hash_tfm(X)                              X
+       #define crypto_alloc_hash(X, Y, Z)              crypto_alloc_tfm(X, mode)
+       #define crypto_hash_digestsize(X)               crypto_tfm_alg_digestsize(X)
+       #define crypto_hash_digest(W, X, Y, Z)  \
+                               crypto_digest_digest((W)->tfm, X, sg_num, Z)
+
+       /* Asymmetric Cipher */
+       #define crypto_has_cipher(X, Y, Z)              crypto_alg_available(X, 0)
+
+       /* Compression */
+       #define crypto_has_comp(X, Y, Z)                crypto_alg_available(X, 0)
+       #define crypto_comp_tfm(X)                              X
+       #define crypto_comp_cast(X)                             X
+       #define crypto_alloc_comp(X, Y, Z)              crypto_alloc_tfm(X, mode)
+#else
+       #define ecb(X)  "ecb(" #X ")"
+       #define cbc(X)  "cbc(" #X ")"
+       #define hmac(X) "hmac(" #X ")"
+#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
+
+struct crypto_details
+{
+       char *alg_name;
+       int mode;
+       int sw_type;
+};
+
+/*
+ * This needs to be kept updated with CRYPTO_xxx list (cryptodev.h).
+ * If the Algorithm is not supported, then insert a {NULL, 0, 0} entry.
+ *
+ * IMPORTANT: The index to the array IS CRYPTO_xxx.
+ */
+static struct crypto_details crypto_details[CRYPTO_ALGORITHM_MAX + 1] = {
+       { NULL,              0,                   0 },
+       /* CRYPTO_xxx index starts at 1 */
+       { cbc(des),          CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { cbc(des3_ede),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { cbc(blowfish),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { cbc(cast5),        CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { cbc(skipjack),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { hmac(md5),         0,                   SW_TYPE_HMAC },
+       { hmac(sha1),        0,                   SW_TYPE_HMAC },
+       { hmac(ripemd160),   0,                   SW_TYPE_HMAC },
+       { "md5-kpdk??",      0,                   SW_TYPE_HASH },
+       { "sha1-kpdk??",     0,                   SW_TYPE_HASH },
+       { cbc(aes),          CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { ecb(arc4),         CRYPTO_TFM_MODE_ECB, SW_TYPE_BLKCIPHER },
+       { "md5",             0,                   SW_TYPE_HASH },
+       { "sha1",            0,                   SW_TYPE_HASH },
+       { hmac(digest_null), 0,                   SW_TYPE_HMAC },
+       { cbc(cipher_null),  CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { "deflate",         0,                   SW_TYPE_COMP },
+       { hmac(sha256),      0,                   SW_TYPE_HMAC },
+       { hmac(sha384),      0,                   SW_TYPE_HMAC },
+       { hmac(sha512),      0,                   SW_TYPE_HMAC },
+       { cbc(camellia),     CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
+       { "sha256",          0,                   SW_TYPE_HASH },
+       { "sha384",          0,                   SW_TYPE_HASH },
+       { "sha512",          0,                   SW_TYPE_HASH },
+       { "ripemd160",       0,                   SW_TYPE_HASH },
+};
+
+int32_t swcr_id = -1;
+module_param(swcr_id, int, 0444);
+MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
+
+int swcr_fail_if_compression_grows = 1;
+module_param(swcr_fail_if_compression_grows, int, 0644);
+MODULE_PARM_DESC(swcr_fail_if_compression_grows,
+                "Treat compression that results in more data as a failure");
+
+static struct swcr_data **swcr_sessions = NULL;
+static u_int32_t swcr_sesnum = 0;
+
+static int swcr_process(device_t, struct cryptop *, int);
+static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
+static int swcr_freesession(device_t, u_int64_t);
+
+static device_method_t swcr_methods = {
+       /* crypto device methods */
+       DEVMETHOD(cryptodev_newsession, swcr_newsession),
+       DEVMETHOD(cryptodev_freesession,swcr_freesession),
+       DEVMETHOD(cryptodev_process,    swcr_process),
+};
+
+#define debug swcr_debug
+int swcr_debug = 0;
+module_param(swcr_debug, int, 0644);
+MODULE_PARM_DESC(swcr_debug, "Enable debug");
+
+/*
+ * Generate a new software session.
+ */
+static int
+swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
+{
+       struct swcr_data **swd;
+       u_int32_t i;
+       int error;
+       char *algo;
+       int mode, sw_type;
+
+       dprintk("%s()\n", __FUNCTION__);
+       if (sid == NULL || cri == NULL) {
+               dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
+               return EINVAL;
+       }
+
+       if (swcr_sessions) {
+               for (i = 1; i < swcr_sesnum; i++)
+                       if (swcr_sessions[i] == NULL)
+                               break;
+       } else
+               i = 1;          /* NB: to silence compiler warning */
+
+       if (swcr_sessions == NULL || i == swcr_sesnum) {
+               if (swcr_sessions == NULL) {
+                       i = 1; /* We leave swcr_sessions[0] empty */
+                       swcr_sesnum = CRYPTO_SW_SESSIONS;
+               } else
+                       swcr_sesnum *= 2;
+
+               swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC);
+               if (swd == NULL) {
+                       /* Reset session number */
+                       if (swcr_sesnum == CRYPTO_SW_SESSIONS)
+                               swcr_sesnum = 0;
+                       else
+                               swcr_sesnum /= 2;
+                       dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+                       return ENOBUFS;
+               }
+               memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));
+
+               /* Copy existing sessions */
+               if (swcr_sessions) {
+                       memcpy(swd, swcr_sessions,
+                           (swcr_sesnum / 2) * sizeof(struct swcr_data *));
+                       kfree(swcr_sessions);
+               }
+
+               swcr_sessions = swd;
+       }
+
+       swd = &swcr_sessions[i];
+       *sid = i;
+
+       while (cri) {
+               *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),
+                               SLAB_ATOMIC);
+               if (*swd == NULL) {
+                       swcr_freesession(NULL, i);
+                       dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+                       return ENOBUFS;
+               }
+               memset(*swd, 0, sizeof(struct swcr_data));
+
+               if (cri->cri_alg > CRYPTO_ALGORITHM_MAX) {
+                       printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg);
+                       swcr_freesession(NULL, i);
+                       return EINVAL;
+               }
+
+               algo = crypto_details[cri->cri_alg].alg_name;
+               if (!algo || !*algo) {
+                       printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg);
+                       swcr_freesession(NULL, i);
+                       return EINVAL;
+               }
+
+               mode = crypto_details[cri->cri_alg].mode;
+               sw_type = crypto_details[cri->cri_alg].sw_type;
+
+               /* Algorithm specific configuration */
+               switch (cri->cri_alg) {
+               case CRYPTO_NULL_CBC:
+                       cri->cri_klen = 0; /* make it work with crypto API */
+                       break;
+               default:
+                       break;
+               }
+
+               if (sw_type == SW_TYPE_BLKCIPHER) {
+                       dprintk("%s crypto_alloc_blkcipher(%s, 0x%x)\n", __FUNCTION__,
+                                       algo, mode);
+
+                       (*swd)->sw_tfm = crypto_blkcipher_tfm(
+                                                               crypto_alloc_blkcipher(algo, 0,
+                                                                       CRYPTO_ALG_ASYNC));
+                       if (!(*swd)->sw_tfm) {
+                               dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s,0x%x)\n",
+                                               algo,mode);
+                               swcr_freesession(NULL, i);
+                               return EINVAL;
+                       }
+
+                       if (debug) {
+                               dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d",
+                                               __FUNCTION__,cri->cri_klen,(cri->cri_klen + 7)/8);
+                               for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
+                               {
+                                       dprintk("%s0x%x", (i % 8) ? " " : "\n    ",cri->cri_key[i]);
+                               }
+                               dprintk("\n");
+                       }
+                       error = crypto_blkcipher_setkey(
+                                               crypto_blkcipher_cast((*swd)->sw_tfm), cri->cri_key,
+                                                       (cri->cri_klen + 7) / 8);
+                       if (error) {
+                               printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,
+                                               (*swd)->sw_tfm->crt_flags);
+                               swcr_freesession(NULL, i);
+                               return error;
+                       }
+               } else if (sw_type == SW_TYPE_HMAC || sw_type == SW_TYPE_HASH) {
+                       dprintk("%s crypto_alloc_hash(%s, 0x%x)\n", __FUNCTION__,
+                                       algo, mode);
+
+                       (*swd)->sw_tfm = crypto_hash_tfm(
+                                                               crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC));
+
+                       if (!(*swd)->sw_tfm) {
+                               dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
+                                               algo, mode);
+                               swcr_freesession(NULL, i);
+                               return EINVAL;
+                       }
+
+                       (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8;
+                       (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen,
+                               SLAB_ATOMIC);
+                       if ((*swd)->u.hmac.sw_key == NULL) {
+                               swcr_freesession(NULL, i);
+                               dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+                               return ENOBUFS;
+                       }
+                       memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);
+                       if (cri->cri_mlen) {
+                               (*swd)->u.hmac.sw_mlen = cri->cri_mlen;
+                       } else {
+                               (*swd)->u.hmac.sw_mlen =
+                                               crypto_hash_digestsize(
+                                                               crypto_hash_cast((*swd)->sw_tfm));
+                       }
+               } else if (sw_type == SW_TYPE_COMP) {
+                       (*swd)->sw_tfm = crypto_comp_tfm(
+                                       crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC));
+                       if (!(*swd)->sw_tfm) {
+                               dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n",
+                                               algo, mode);
+                               swcr_freesession(NULL, i);
+                               return EINVAL;
+                       }
+                       (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC);
+                       if ((*swd)->u.sw_comp_buf == NULL) {
+                               swcr_freesession(NULL, i);
+                               dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
+                               return ENOBUFS;
+                       }
+               } else {
+                       printk("cryptosoft: Unhandled sw_type %d\n", sw_type);
+                       swcr_freesession(NULL, i);
+                       return EINVAL;
+               }
+
+               (*swd)->sw_alg = cri->cri_alg;
+               (*swd)->sw_type = sw_type;
+
+               cri = cri->cri_next;
+               swd = &((*swd)->sw_next);
+       }
+       return 0;
+}
+
+/*
+ * Free a session.
+ */
+static int
+swcr_freesession(device_t dev, u_int64_t tid)
+{
+       struct swcr_data *swd;
+       u_int32_t sid = CRYPTO_SESID2LID(tid);
+
+       dprintk("%s()\n", __FUNCTION__);
+       if (sid > swcr_sesnum || swcr_sessions == NULL ||
+                       swcr_sessions[sid] == NULL) {
+               dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+               return(EINVAL);
+       }
+
+       /* Silently accept and return */
+       if (sid == 0)
+               return(0);
+
+       while ((swd = swcr_sessions[sid]) != NULL) {
+               swcr_sessions[sid] = swd->sw_next;
+               if (swd->sw_tfm)
+                       crypto_free_tfm(swd->sw_tfm);
+               if (swd->sw_type == SW_TYPE_COMP) {
+                       if (swd->u.sw_comp_buf)
+                               kfree(swd->u.sw_comp_buf);
+               } else {
+                       if (swd->u.hmac.sw_key)
+                               kfree(swd->u.hmac.sw_key);
+               }
+               kfree(swd);
+       }
+       return 0;
+}
+
+/*
+ * Process a software request.
+ */
+static int
+swcr_process(device_t dev, struct cryptop *crp, int hint)
+{
+       struct cryptodesc *crd;
+       struct swcr_data *sw;
+       u_int32_t lid;
+#define SCATTERLIST_MAX 16
+       struct scatterlist sg[SCATTERLIST_MAX];
+       int sg_num, sg_len, skip;
+       struct sk_buff *skb = NULL;
+       struct uio *uiop = NULL;
+
+       dprintk("%s()\n", __FUNCTION__);
+       /* Sanity check */
+       if (crp == NULL) {
+               dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+               return EINVAL;
+       }
+
+       crp->crp_etype = 0;
+
+       if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
+               dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+               crp->crp_etype = EINVAL;
+               goto done;
+       }
+
+       lid = crp->crp_sid & 0xffffffff;
+       if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL ||
+                       swcr_sessions[lid] == NULL) {
+               crp->crp_etype = ENOENT;
+               dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
+               goto done;
+       }
+
+       /*
+        * do some error checking outside of the loop for SKB and IOV processing
+        * this leaves us with valid skb or uiop pointers for later
+        */
+       if (crp->crp_flags & CRYPTO_F_SKBUF) {
+               skb = (struct sk_buff *) crp->crp_buf;
+               if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
+                       printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__,
+                                       skb_shinfo(skb)->nr_frags);
+                       goto done;
+               }
+       } else if (crp->crp_flags & CRYPTO_F_IOV) {
+               uiop = (struct uio *) crp->crp_buf;
+               if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
+                       printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__,
+                                       uiop->uio_iovcnt);
+                       goto done;
+               }
+       }
+
+       /* Go through crypto descriptors, processing as we go */
+       for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
+               /*
+                * Find the crypto context.
+                *
+                * XXX Note that the logic here prevents us from having
+                * XXX the same algorithm multiple times in a session
+                * XXX (or rather, we can but it won't give us the right
+                * XXX results). To do that, we'd need some way of differentiating
+                * XXX between the various instances of an algorithm (so we can
+                * XXX locate the correct crypto context).
+                */
+               for (sw = swcr_sessions[lid]; sw && sw->sw_alg != crd->crd_alg;
+                               sw = sw->sw_next)
+                       ;
+
+               /* No such context ? */
+               if (sw == NULL) {
+                       crp->crp_etype = EINVAL;
+                       dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+                       goto done;
+               }
+
+               skip = crd->crd_skip;
+
+               /*
+                * setup the SG list skip from the start of the buffer
+                */
+               memset(sg, 0, sizeof(sg));
+               if (crp->crp_flags & CRYPTO_F_SKBUF) {
+                       int i, len;
+
+                       sg_num = 0;
+                       sg_len = 0;
+
+                       if (skip < skb_headlen(skb)) {
+                               len = skb_headlen(skb) - skip;
+                               if (len + sg_len > crd->crd_len)
+                                       len = crd->crd_len - sg_len;
+                               sg_set_page(&sg[sg_num],
+                                       virt_to_page(skb->data + skip), len,
+                                       offset_in_page(skb->data + skip));
+                               sg_len += len;
+                               sg_num++;
+                               skip = 0;
+                       } else
+                               skip -= skb_headlen(skb);
+
+                       for (i = 0; sg_len < crd->crd_len &&
+                                               i < skb_shinfo(skb)->nr_frags &&
+                                               sg_num < SCATTERLIST_MAX; i++) {
+                               if (skip < skb_shinfo(skb)->frags[i].size) {
+                                       len = skb_shinfo(skb)->frags[i].size - skip;
+                                       if (len + sg_len > crd->crd_len)
+                                               len = crd->crd_len - sg_len;
+                                       sg_set_page(&sg[sg_num],
+                                               skb_shinfo(skb)->frags[i].page,
+                                               len,
+                                               skb_shinfo(skb)->frags[i].page_offset + skip);
+                                       sg_len += len;
+                                       sg_num++;
+                                       skip = 0;
+                               } else
+                                       skip -= skb_shinfo(skb)->frags[i].size;
+                       }
+               } else if (crp->crp_flags & CRYPTO_F_IOV) {
+                       int len;
+
+                       sg_len = 0;
+                       for (sg_num = 0; sg_len <= crd->crd_len &&
+                                       sg_num < uiop->uio_iovcnt &&
+                                       sg_num < SCATTERLIST_MAX; sg_num++) {
+                               if (skip <= uiop->uio_iov[sg_num].iov_len) {
+                                       len = uiop->uio_iov[sg_num].iov_len - skip;
+                                       if (len + sg_len > crd->crd_len)
+                                               len = crd->crd_len - sg_len;
+                                       sg_set_page(&sg[sg_num],
+                                               virt_to_page(uiop->uio_iov[sg_num].iov_base+skip),
+                                               len,
+                                               offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
+                                       sg_len += len;
+                                       skip = 0;
+                               } else 
+                                       skip -= uiop->uio_iov[sg_num].iov_len;
+                       }
+               } else {
+                       sg_len = (crp->crp_ilen - skip);
+                       if (sg_len > crd->crd_len)
+                               sg_len = crd->crd_len;
+                       sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip),
+                               sg_len, offset_in_page(crp->crp_buf + skip));
+                       sg_num = 1;
+               }
+
+
+               switch (sw->sw_type) {
+               case SW_TYPE_BLKCIPHER: {
+                       unsigned char iv[EALG_MAX_BLOCK_LEN];
+                       unsigned char *ivp = iv;
+                       int ivsize = 
+                               crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm));
+                       struct blkcipher_desc desc;
+
+                       if (sg_len < crypto_blkcipher_blocksize(
+                                       crypto_blkcipher_cast(sw->sw_tfm))) {
+                               crp->crp_etype = EINVAL;
+                               dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
+                                               sg_len, crypto_blkcipher_blocksize(
+                                                       crypto_blkcipher_cast(sw->sw_tfm)));
+                               goto done;
+                       }
+
+                       if (ivsize > sizeof(iv)) {
+                               crp->crp_etype = EINVAL;
+                               dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+                               goto done;
+                       }
+
+                       if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
+                               int i, error;
+
+                               if (debug) {
+                                       dprintk("%s key:", __FUNCTION__);
+                                       for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
+                                               dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
+                                                               crd->crd_key[i]);
+                                       dprintk("\n");
+                               }
+                               error = crypto_blkcipher_setkey(
+                                                       crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key,
+                                                       (crd->crd_klen + 7) / 8);
+                               if (error) {
+                                       dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
+                                                       error, sw->sw_tfm->crt_flags);
+                                       crp->crp_etype = -error;
+                               }
+                       }
+
+                       memset(&desc, 0, sizeof(desc));
+                       desc.tfm = crypto_blkcipher_cast(sw->sw_tfm);
+
+                       if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
+
+                               if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
+                                       ivp = crd->crd_iv;
+                               } else {
+                                       get_random_bytes(ivp, ivsize);
+                               }
+                               /*
+                                * do we have to copy the IV back to the buffer ?
+                                */
+                               if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
+                                       crypto_copyback(crp->crp_flags, crp->crp_buf,
+                                                       crd->crd_inject, ivsize, (caddr_t)ivp);
+                               }
+                               desc.info = ivp;
+                               crypto_blkcipher_encrypt_iv(&desc, sg, sg, sg_len);
+
+                       } else { /*decrypt */
+
+                               if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
+                                       ivp = crd->crd_iv;
+                               } else {
+                                       crypto_copydata(crp->crp_flags, crp->crp_buf,
+                                                       crd->crd_inject, ivsize, (caddr_t)ivp);
+                               }
+                               desc.info = ivp;
+                               crypto_blkcipher_decrypt_iv(&desc, sg, sg, sg_len);
+                       }
+                       } break;
+               case SW_TYPE_HMAC:
+               case SW_TYPE_HASH:
+                       {
+                       char result[HASH_MAX_LEN];
+                       struct hash_desc desc;
+
+                       /* check we have room for the result */
+                       if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
+                               dprintk(
+                       "cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d digestsize=%d\n",
+                                               crp->crp_ilen, crd->crd_skip + sg_len, crd->crd_inject,
+                                               sw->u.hmac.sw_mlen);
+                               crp->crp_etype = EINVAL;
+                               goto done;
+                       }
+
+                       memset(&desc, 0, sizeof(desc));
+                       desc.tfm = crypto_hash_cast(sw->sw_tfm);
+
+                       memset(result, 0, sizeof(result));
+
+                       if (sw->sw_type == SW_TYPE_HMAC) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+                               crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,
+                                               sg, sg_num, result);
+#else
+                               crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key,
+                                               sw->u.hmac.sw_klen);
+                               crypto_hash_digest(&desc, sg, sg_len, result);
+#endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
+                               
+                       } else { /* SW_TYPE_HASH */
+                               crypto_hash_digest(&desc, sg, sg_len, result);
+                       }
+
+                       crypto_copyback(crp->crp_flags, crp->crp_buf,
+                                       crd->crd_inject, sw->u.hmac.sw_mlen, result);
+                       }
+                       break;
+
+               case SW_TYPE_COMP: {
+                       void *ibuf = NULL;
+                       void *obuf = sw->u.sw_comp_buf;
+                       int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN;
+                       int ret = 0;
+
+                       /*
+                        * we need to use an additional copy if there is more than one
+                        * input chunk since the kernel comp routines do not handle
+                        * SG yet.  Otherwise we just use the input buffer as is.
+                        * Rather than allocate another buffer we just split the tmp
+                        * buffer we already have.
+                        * Perhaps we should just use zlib directly ?
+                        */
+                       if (sg_num > 1) {
+                               int blk;
+
+                               ibuf = obuf;
+                               for (blk = 0; blk < sg_num; blk++) {
+                                       memcpy(obuf, sg_virt(&sg[blk]),
+                                                       sg[blk].length);
+                                       obuf += sg[blk].length;
+                               }
+                               olen -= sg_len;
+                       } else
+                               ibuf = sg_virt(&sg[0]);
+
+                       if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */
+                               ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm),
+                                               ibuf, ilen, obuf, &olen);
+                               if (!ret && olen > crd->crd_len) {
+                                       dprintk("cryptosoft: ERANGE compress %d into %d\n",
+                                                       crd->crd_len, olen);
+                                       if (swcr_fail_if_compression_grows)
+                                               ret = ERANGE;
+                               }
+                       } else { /* decompress */
+                               ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm),
+                                               ibuf, ilen, obuf, &olen);
+                               if (!ret && (olen + crd->crd_inject) > crp->crp_olen) {
+                                       dprintk("cryptosoft: ETOOSMALL decompress %d into %d, "
+                                                       "space for %d,at offset %d\n",
+                                                       crd->crd_len, olen, crp->crp_olen, crd->crd_inject);
+                                       ret = ETOOSMALL;
+                               }
+                       }
+                       if (ret)
+                               dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret);
+
+                       /*
+                        * on success copy result back,
+                        * linux crpyto API returns -errno,  we need to fix that
+                        */
+                       crp->crp_etype = ret < 0 ? -ret : ret;
+                       if (ret == 0) {
+                               /* copy back the result and return it's size */
+                               crypto_copyback(crp->crp_flags, crp->crp_buf,
+                                               crd->crd_inject, olen, obuf);
+                               crp->crp_olen = olen;
+                       }
+
+
+                       } break;
+
+               default:
+                       /* Unknown/unsupported algorithm */
+                       dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
+                       crp->crp_etype = EINVAL;
+                       goto done;
+               }
+       }
+
+done:
+       crypto_done(crp);
+       return 0;
+}
+
+static int
+cryptosoft_init(void)
+{
+       int i, sw_type, mode;
+       char *algo;
+
+       dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init);
+
+       softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods);
+
+       swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc),
+                       CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
+       if (swcr_id < 0) {
+               printk("Software crypto device cannot initialize!");
+               return -ENODEV;
+       }
+
+#define        REGISTER(alg) \
+               crypto_register(swcr_id, alg, 0,0);
+
+       for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; ++i)
+       {
+               
+               algo = crypto_details[i].alg_name;
+               if (!algo || !*algo)
+               {
+                       dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i);
+                       continue;
+               }
+
+               mode = crypto_details[i].mode;
+               sw_type = crypto_details[i].sw_type;
+
+               switch (sw_type)
+               {
+                       case SW_TYPE_CIPHER:
+                               if (crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC))
+                               {
+                                       REGISTER(i);
+                               }
+                               else
+                               {
+                                       dprintk("%s:CIPHER algorithm %d:'%s' not supported\n",
+                                                               __FUNCTION__, i, algo);
+                               }
+                               break;
+                       case SW_TYPE_HMAC:
+                               if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC))
+                               {
+                                       REGISTER(i);
+                               }
+                               else
+                               {
+                                       dprintk("%s:HMAC algorithm %d:'%s' not supported\n",
+                                                               __FUNCTION__, i, algo);
+                               }
+                               break;
+                       case SW_TYPE_HASH:
+                               if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC))
+                               {
+                                       REGISTER(i);
+                               }
+                               else
+                               {
+                                       dprintk("%s:HASH algorithm %d:'%s' not supported\n",
+                                                               __FUNCTION__, i, algo);
+                               }
+                               break;
+                       case SW_TYPE_COMP:
+                               if (crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC))
+                               {
+                                       REGISTER(i);
+                               }
+                               else
+                               {
+                                       dprintk("%s:COMP algorithm %d:'%s' not supported\n",
+                                                               __FUNCTION__, i, algo);
+                               }
+                               break;
+                       case SW_TYPE_BLKCIPHER:
+                               if (crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC))
+                               {
+                                       REGISTER(i);
+                               }
+                               else
+                               {
+                                       dprintk("%s:BLKCIPHER algorithm %d:'%s' not supported\n",
+                                                               __FUNCTION__, i, algo);
+                               }
+                               break;
+                       default:
+                               dprintk(
+                               "%s:Algorithm Type %d not supported (algorithm %d:'%s')\n",
+                                       __FUNCTION__, sw_type, i, algo);
+                               break;
+               }
+       }
+
+       return(0);
+}
+
+static void
+cryptosoft_exit(void)
+{
+       dprintk("%s()\n", __FUNCTION__);
+       crypto_unregister_all(swcr_id);
+       swcr_id = -1;
+}
+
+module_init(cryptosoft_init);
+module_exit(cryptosoft_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
+MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");
diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/Makefile b/target/linux/generic-2.6/files/crypto/ocf/ep80579/Makefile
new file mode 100644 (file)
index 0000000..19ff6eb
--- /dev/null
@@ -0,0 +1,107 @@
+#########################################################################
+#
+#  Targets supported
+#  all     - builds everything and installs
+#  install - identical to all
+#  depend  - build dependencies
+#  clean   - clears derived objects except the .depend files
+#  distclean- clears all derived objects and the .depend file
+#  
+# @par
+# This file is provided under a dual BSD/GPLv2 license.  When using or 
+#   redistributing this file, you may do so under either license.
+# 
+#   GPL LICENSE SUMMARY
+# 
+#   Copyright(c) 2007,2008 Intel Corporation. All rights reserved.
+# 
+#   This program is free software; you can redistribute it and/or modify 
+#   it under the terms of version 2 of the GNU General Public License as
+#   published by the Free Software Foundation.
+# 
+#   This program is distributed in the hope that it will be useful, but 
+#   WITHOUT ANY WARRANTY; without even the implied warranty of 
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+#   General Public License for more details.
+# 
+#   You should have received a copy of the GNU General Public License 
+#   along with this program; if not, write to the Free Software 
+#   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#   The full GNU General Public License is included in this distribution 
+#   in the file called LICENSE.GPL.
+# 
+#   Contact Information:
+#   Intel Corporation
+# 
+#   BSD LICENSE 
+# 
+#   Copyright(c) 2007,2008 Intel Corporation. All rights reserved.
+#   All rights reserved.
+# 
+#   Redistribution and use in source and binary forms, with or without 
+#   modification, are permitted provided that the following conditions 
+#   are met:
+# 
+#     * Redistributions of source code must retain the above copyright 
+#       notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT 
+#   OWNER 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.
+# 
+# 
+#  version: Security.L.1.0.130
+############################################################################
+
+
+####################Common variables and definitions########################
+
+# Ensure The ENV_DIR environmental var is defined.
+ifndef ICP_ENV_DIR
+$(error ICP_ENV_DIR is undefined. Please set the path to your environment makefile \
+        "-> setenv ICP_ENV_DIR <path>")
+endif
+
+#Add your project environment Makefile
+include $(ICP_ENV_DIR)/environment.mk
+
+#include the makefile with all the default and common Make variable definitions
+include $(ICP_BUILDSYSTEM_PATH)/build_files/common.mk
+
+#Add the name for the executable, Library or Module output definitions
+OUTPUT_NAME= icp_ocf
+
+# List of Source Files to be compiled 
+SOURCES= icp_common.c icp_sym.c icp_asym.c
+
+#common includes between all supported OSes
+INCLUDES= -I $(ICP_API_DIR) -I$(ICP_LAC_API) \
+-I$(ICP_OCF_SRC_DIR)
+
+# The location of the os level makefile needs to be changed.
+include $(ICP_ENV_DIR)/$(ICP_OS)_$(ICP_OS_LEVEL).mk
+
+# On the line directly below list the outputs you wish to build for,
+# e.g "lib_static lib_shared exe module" as show below
+install: module
+
+###################Include rules makefiles########################
+include $(ICP_BUILDSYSTEM_PATH)/build_files/rules.mk
+###################End of Rules inclusion#########################
+
+
diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/environment.mk b/target/linux/generic-2.6/files/crypto/ocf/ep80579/environment.mk
new file mode 100644 (file)
index 0000000..a674b45
--- /dev/null
@@ -0,0 +1,75 @@
+ ###########################################################################
+ #
+# This file is provided under a dual BSD/GPLv2 license.  When using or 
+#   redistributing this file, you may do so under either license.
+# 
+#   GPL LICENSE SUMMARY
+# 
+#   Copyright(c) 2007,2008 Intel Corporation. All rights reserved.
+# 
+#   This program is free software; you can redistribute it and/or modify 
+#   it under the terms of version 2 of the GNU General Public License as
+#   published by the Free Software Foundation.
+# 
+#   This program is distributed in the hope that it will be useful, but 
+#   WITHOUT ANY WARRANTY; without even the implied warranty of 
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+#   General Public License for more details.
+# 
+#   You should have received a copy of the GNU General Public License 
+#   along with this program; if not, write to the Free Software 
+#   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#   The full GNU General Public License is included in this distribution 
+#   in the file called LICENSE.GPL.
+# 
+#   Contact Information:
+#   Intel Corporation
+# 
+#   BSD LICENSE 
+# 
+#   Copyright(c) 2007,2008 Intel Corporation. All rights reserved.
+#   All rights reserved.
+# 
+#   Redistribution and use in source and binary forms, with or without 
+#   modification, are permitted provided that the following conditions 
+#   are met:
+# 
+#     * Redistributions of source code must retain the above copyright 
+#       notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT 
+#   OWNER 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.
+# 
+# 
+#  version: Security.L.1.0.130
+ #
+ ###########################################################################
+
+
+ICP_LAC_API=$(ICP_ROOT)/Acceleration/include/lac
+ICP_BTR_API=$(ICP_ROOT)/Acceleration/include/btr
+ICP_API_DIR=$(ICP_ROOT)/Acceleration/include
+ICP_OCF_SHIM_DIR?=$(KERNEL_SOURCE_ROOT)/crypto/ocf/
+
+ICP_OS_LEVEL?=kernel_space
+
+ICP_OS?=linux_2.6
+
+ICP_CORE?=ia
+
diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_asym.c b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_asym.c
new file mode 100644 (file)
index 0000000..1a9bd28
--- /dev/null
@@ -0,0 +1,1375 @@
+/***************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or 
+ *   redistributing this file, you may do so under either license.
+ * 
+ *   GPL LICENSE SUMMARY
+ * 
+ *   Copyright(c) 2007,2008 Intel Corporation. All rights reserved.
+ * 
+ *   This program is free software; you can redistribute it and/or modify 
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ * 
+ *   This program is distributed in the hope that it will be useful, but 
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ *   General Public License for more details.
+ * 
+ *   You should have received a copy of the GNU General Public License 
+ *   along with this program; if not, write to the Free Software 
+ *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *   The full GNU General Public License is included in this distribution 
+ *   in the file called LICENSE.GPL.
+ * 
+ *   Contact Information:
+ *   Intel Corporation
+ * 
+ *   BSD LICENSE 
+ * 
+ *   Copyright(c) 2007,2008 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ * 
+ *   Redistribution and use in source and binary forms, with or without 
+ *   modification, are permitted provided that the following conditions 
+ *   are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ *       notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT 
+ *   OWNER 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.
+ * 
+ * 
+ *  version: Security.L.1.0.130
+ *
+ ***************************************************************************/
+
+#include "icp_ocf.h"
+
+/*The following define values (containing the word 'INDEX') are used to find
+the index of each input buffer of the crypto_kop struct (see OCF cryptodev.h).
+These values were found through analysis of the OCF OpenSSL patch. If the
+calling program uses different input buffer positions, these defines will have
+to be changed.*/
+
+/*DIFFIE HELLMAN buffer index values*/
+#define ICP_DH_KRP_PARAM_PRIME_INDEX                           (0)
+#define ICP_DH_KRP_PARAM_BASE_INDEX                            (1)
+#define ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX                   (2)
+#define ICP_DH_KRP_PARAM_RESULT_INDEX                          (3)
+
+/*MOD EXP buffer index values*/
+#define ICP_MOD_EXP_KRP_PARAM_BASE_INDEX                       (0)
+#define ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX                   (1)
+#define ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX                    (2)
+#define ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX                     (3)
+
+#define SINGLE_BYTE_VALUE                                      (4)
+
+/*MOD EXP CRT buffer index values*/
+#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX                        (0)
+#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX                        (1)
+#define ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX                      (2)
+#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX            (3)
+#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX            (4)
+#define ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX             (5)
+#define ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX                 (6)
+
+/*DSA sign buffer index values*/
+#define ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX                      (0)
+#define ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX                   (1)
+#define ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX                   (2)
+#define ICP_DSA_SIGN_KRP_PARAM_G_INDEX                         (3)
+#define ICP_DSA_SIGN_KRP_PARAM_X_INDEX                         (4)
+#define ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX                  (5)
+#define ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX                  (6)
+
+/*DSA verify buffer index values*/
+#define ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX                    (0)
+#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX                 (1)
+#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX                 (2)
+#define ICP_DSA_VERIFY_KRP_PARAM_G_INDEX                       (3)
+#define ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX                  (4)
+#define ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX                   (5)
+#define ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX                   (6)
+
+/*DSA sign prime Q vs random number K size check values*/
+#define DONT_RUN_LESS_THAN_CHECK                               (0)
+#define FAIL_A_IS_GREATER_THAN_B                               (1)
+#define FAIL_A_IS_EQUAL_TO_B                                   (1)
+#define SUCCESS_A_IS_LESS_THAN_B                               (0)
+#define DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS             (500)
+
+/* We need to set a cryptokp success value just in case it is set or allocated
+   and not set to zero outside of this module */
+#define CRYPTO_OP_SUCCESS                                      (0)
+
+static int icp_ocfDrvDHComputeKey(struct cryptkop *krp);
+
+static int icp_ocfDrvModExp(struct cryptkop *krp);
+
+static int icp_ocfDrvModExpCRT(struct cryptkop *krp);
+
+static int
+icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck);
+
+static int icp_ocfDrvDsaSign(struct cryptkop *krp);
+
+static int icp_ocfDrvDsaVerify(struct cryptkop *krp);
+
+static void
+icp_ocfDrvDhP1CallBack(void *callbackTag,
+                      CpaStatus status,
+                      void *pOpData, CpaFlatBuffer * pLocalOctetStringPV);
+
+static void
+icp_ocfDrvModExpCallBack(void *callbackTag,
+                        CpaStatus status,
+                        void *pOpData, CpaFlatBuffer * pResult);
+
+static void
+icp_ocfDrvModExpCRTCallBack(void *callbackTag,
+                           CpaStatus status,
+                           void *pOpData, CpaFlatBuffer * pOutputData);
+
+static void
+icp_ocfDrvDsaVerifyCallBack(void *callbackTag,
+                           CpaStatus status,
+                           void *pOpData, CpaBoolean verifyStatus);
+
+static void
+icp_ocfDrvDsaRSSignCallBack(void *callbackTag,
+                           CpaStatus status,
+                           void *pOpData,
+                           CpaBoolean protocolStatus,
+                           CpaFlatBuffer * pR, CpaFlatBuffer * pS);
+
+/* Name        : icp_ocfDrvPkeProcess
+ *
+ * Description : This function will choose which PKE process to follow
+ * based on the input arguments
+ */
+int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+
+       if (NULL == krp) {
+               DPRINTK("%s(): Invalid input parameters, cryptkop = %p\n",
+                       __FUNCTION__, krp);
+               return EINVAL;
+       }
+
+       if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) {
+               krp->krp_status = ECANCELED;
+               return ECANCELED;
+       }
+
+       switch (krp->krp_op) {
+       case CRK_DH_COMPUTE_KEY:
+               DPRINTK("%s() doing DH_COMPUTE_KEY\n", __FUNCTION__);
+               lacStatus = icp_ocfDrvDHComputeKey(krp);
+               if (CPA_STATUS_SUCCESS != lacStatus) {
+                       EPRINTK("%s(): icp_ocfDrvDHComputeKey failed "
+                               "(%d).\n", __FUNCTION__, lacStatus);
+                       krp->krp_status = ECANCELED;
+                       return ECANCELED;
+               }
+
+               break;
+
+       case CRK_MOD_EXP:
+               DPRINTK("%s() doing MOD_EXP \n", __FUNCTION__);
+               lacStatus = icp_ocfDrvModExp(krp);
+               if (CPA_STATUS_SUCCESS != lacStatus) {
+                       EPRINTK("%s(): icp_ocfDrvModExp failed (%d).\n",
+                               __FUNCTION__, lacStatus);
+                       krp->krp_status = ECANCELED;
+                       return ECANCELED;
+               }
+
+               break;
+
+       case CRK_MOD_EXP_CRT:
+               DPRINTK("%s() doing MOD_EXP_CRT \n", __FUNCTION__);
+               lacStatus = icp_ocfDrvModExpCRT(krp);
+               if (CPA_STATUS_SUCCESS != lacStatus) {
+                       EPRINTK("%s(): icp_ocfDrvModExpCRT "
+                               "failed (%d).\n", __FUNCTION__, lacStatus);
+                       krp->krp_status = ECANCELED;
+                       return ECANCELED;
+               }
+
+               break;
+
+       case CRK_DSA_SIGN:
+               DPRINTK("%s() doing DSA_SIGN \n", __FUNCTION__);
+               lacStatus = icp_ocfDrvDsaSign(krp);
+               if (CPA_STATUS_SUCCESS != lacStatus) {
+                       EPRINTK("%s(): icp_ocfDrvDsaSign "
+                               "failed (%d).\n", __FUNCTION__, lacStatus);
+                       krp->krp_status = ECANCELED;
+                       return ECANCELED;
+               }
+
+               break;
+
+       case CRK_DSA_VERIFY:
+               DPRINTK("%s() doing DSA_VERIFY \n", __FUNCTION__);
+               lacStatus = icp_ocfDrvDsaVerify(krp);
+               if (CPA_STATUS_SUCCESS != lacStatus) {
+                       EPRINTK("%s(): icp_ocfDrvDsaVerify "
+                               "failed (%d).\n", __FUNCTION__, lacStatus);
+                       krp->krp_status = ECANCELED;
+                       return ECANCELED;
+               }
+
+               break;
+
+       default:
+               EPRINTK("%s(): Asymettric function not "
+                       "supported (%d).\n", __FUNCTION__, krp->krp_op);
+               krp->krp_status = EOPNOTSUPP;
+               return EOPNOTSUPP;
+       }
+
+       return ICP_OCF_DRV_STATUS_SUCCESS;
+}
+
+/* Name        : icp_ocfDrvSwapBytes
+ *
+ * Description : This function is used to swap the byte order of a buffer.
+ * It has been seen that in general we are passed little endian byte order
+ * buffers, but LAC only accepts big endian byte order buffers.
+ */
+static void inline
+icp_ocfDrvSwapBytes(u_int8_t * num, u_int32_t buff_len_bytes)
+{
+
+       int i;
+       u_int8_t *end_ptr;
+       u_int8_t hold_val;
+
+       end_ptr = num + (buff_len_bytes - 1);
+       buff_len_bytes = buff_len_bytes >> 1;
+       for (i = 0; i < buff_len_bytes; i++) {
+               hold_val = *num;
+               *num = *end_ptr;
+               num++;
+               *end_ptr = hold_val;
+               end_ptr--;
+       }
+}
+
+/* Name        : icp_ocfDrvDHComputeKey
+ *
+ * Description : This function will map Diffie Hellman calls from OCF
+ * to the LAC API. OCF uses this function for Diffie Hellman Phase1 and
+ * Phase2. LAC has a separate Diffie Hellman Phase2 call, however both phases
+ * break down to a modular exponentiation.
+ */
+static int icp_ocfDrvDHComputeKey(struct cryptkop *krp)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+       void *callbackTag = NULL;
+       CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL;
+       CpaFlatBuffer *pLocalOctetStringPV = NULL;
+       uint32_t dh_prime_len_bytes = 0, dh_prime_len_bits = 0;
+
+       /* Input checks - check prime is a multiple of 8 bits to allow for
+          allocation later */
+       dh_prime_len_bits =
+           (krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_nbits);
+
+       /* LAC can reject prime lengths based on prime key sizes, we just
+          need to make sure we can allocate space for the base and
+          exponent buffers correctly */
+       if ((dh_prime_len_bits % NUM_BITS_IN_BYTE) != 0) {
+               APRINTK("%s(): Warning Prime number buffer size is not a "
+                       "multiple of 8 bits\n", __FUNCTION__);
+       }
+
+       /* Result storage space should be the same size as the prime as this
+          value can take up the same amount of storage space */
+       if (dh_prime_len_bits !=
+           krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits) {
+               DPRINTK("%s(): Return Buffer must be the same size "
+                       "as the Prime buffer\n", __FUNCTION__);
+               krp->krp_status = EINVAL;
+               return EINVAL;
+       }
+       /* Switch to size in bytes */
+       BITS_TO_BYTES(dh_prime_len_bytes, dh_prime_len_bits);
+
+       callbackTag = krp;
+
+       pPhase1OpData = kmem_cache_zalloc(drvDH_zone, GFP_KERNEL);
+       if (NULL == pPhase1OpData) {
+               APRINTK("%s():Failed to get memory for key gen data\n",
+                       __FUNCTION__);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       pLocalOctetStringPV = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL);
+       if (NULL == pLocalOctetStringPV) {
+               APRINTK("%s():Failed to get memory for pLocalOctetStringPV\n",
+                       __FUNCTION__);
+               kmem_cache_free(drvDH_zone, pPhase1OpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       /* Link parameters */
+       pPhase1OpData->primeP.pData =
+           krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_p;
+
+       pPhase1OpData->primeP.dataLenInBytes = dh_prime_len_bytes;
+
+       icp_ocfDrvSwapBytes(pPhase1OpData->primeP.pData, dh_prime_len_bytes);
+
+       pPhase1OpData->baseG.pData =
+           krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_p;
+
+       BITS_TO_BYTES(pPhase1OpData->baseG.dataLenInBytes,
+                     krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_nbits);
+
+       icp_ocfDrvSwapBytes(pPhase1OpData->baseG.pData,
+                           pPhase1OpData->baseG.dataLenInBytes);
+
+       pPhase1OpData->privateValueX.pData =
+           krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].crp_p;
+
+       BITS_TO_BYTES(pPhase1OpData->privateValueX.dataLenInBytes,
+                     krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(pPhase1OpData->privateValueX.pData,
+                           pPhase1OpData->privateValueX.dataLenInBytes);
+
+       /* Output parameters */
+       pLocalOctetStringPV->pData =
+           krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_p;
+
+       BITS_TO_BYTES(pLocalOctetStringPV->dataLenInBytes,
+                     krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits);
+
+       lacStatus = cpaCyDhKeyGenPhase1(CPA_INSTANCE_HANDLE_SINGLE,
+                                       icp_ocfDrvDhP1CallBack,
+                                       callbackTag, pPhase1OpData,
+                                       pLocalOctetStringPV);
+
+       if (CPA_STATUS_SUCCESS != lacStatus) {
+               EPRINTK("%s(): DH Phase 1 Key Gen failed (%d).\n",
+                       __FUNCTION__, lacStatus);
+               icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV);
+               kmem_cache_free(drvDH_zone, pPhase1OpData);
+       }
+
+       return lacStatus;
+}
+
+/* Name        : icp_ocfDrvModExp
+ *
+ * Description : This function will map ordinary Modular Exponentiation calls
+ * from OCF to the LAC API.
+ *
+ */
+static int icp_ocfDrvModExp(struct cryptkop *krp)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+       void *callbackTag = NULL;
+       CpaCyLnModExpOpData *pModExpOpData = NULL;
+       CpaFlatBuffer *pResult = NULL;
+
+       if ((krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits %
+            NUM_BITS_IN_BYTE) != 0) {
+               DPRINTK("%s(): Warning - modulus buffer size (%d) is not a "
+                       "multiple of 8 bits\n", __FUNCTION__,
+                       krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].
+                       crp_nbits);
+       }
+
+       /* Result storage space should be the same size as the prime as this
+          value can take up the same amount of storage space */
+       if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits >
+           krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_nbits) {
+               APRINTK("%s(): Return Buffer size must be the same or"
+                       " greater than the Modulus buffer\n", __FUNCTION__);
+               krp->krp_status = EINVAL;
+               return EINVAL;
+       }
+
+       callbackTag = krp;
+
+       pModExpOpData = kmem_cache_zalloc(drvLnModExp_zone, GFP_KERNEL);
+       if (NULL == pModExpOpData) {
+               APRINTK("%s():Failed to get memory for key gen data\n",
+                       __FUNCTION__);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       pResult = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL);
+       if (NULL == pResult) {
+               APRINTK("%s():Failed to get memory for ModExp result\n",
+                       __FUNCTION__);
+               kmem_cache_free(drvLnModExp_zone, pModExpOpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       /* Link parameters */
+       pModExpOpData->modulus.pData =
+           krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_p;
+       BITS_TO_BYTES(pModExpOpData->modulus.dataLenInBytes,
+                     krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(pModExpOpData->modulus.pData,
+                           pModExpOpData->modulus.dataLenInBytes);
+
+       /*OCF patch to Openswan Pluto regularly sends the base value as 2
+          bits in size. In this case, it has been found it is better to
+          use the base size memory space as the input buffer (if the number
+          is in bits is less than a byte, the number of bits is the input
+          value) */
+       if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits <
+           NUM_BITS_IN_BYTE) {
+               DPRINTK("%s : base is small (%d)\n", __FUNCTION__, krp->
+                       krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits);
+               pModExpOpData->base.dataLenInBytes = SINGLE_BYTE_VALUE;
+               pModExpOpData->base.pData =
+                   (uint8_t *) & (krp->
+                                  krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].
+                                  crp_nbits);
+               *((uint32_t *) pModExpOpData->base.pData) =
+                   htonl(*((uint32_t *) pModExpOpData->base.pData));
+
+       } else {
+
+               DPRINTK("%s : base is big (%d)\n", __FUNCTION__, krp->
+                       krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits);
+               pModExpOpData->base.pData =
+                   krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_p;
+               BITS_TO_BYTES(pModExpOpData->base.dataLenInBytes,
+                             krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].
+                             crp_nbits);
+               icp_ocfDrvSwapBytes(pModExpOpData->base.pData,
+                                   pModExpOpData->base.dataLenInBytes);
+       }
+
+       pModExpOpData->exponent.pData =
+           krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].crp_p;
+       BITS_TO_BYTES(pModExpOpData->exponent.dataLenInBytes,
+                     krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(pModExpOpData->exponent.pData,
+                           pModExpOpData->exponent.dataLenInBytes);
+       /* Output parameters */
+       pResult->pData =
+           krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_p,
+           BITS_TO_BYTES(pResult->dataLenInBytes,
+                         krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].
+                         crp_nbits);
+
+       lacStatus = cpaCyLnModExp(CPA_INSTANCE_HANDLE_SINGLE,
+                                 icp_ocfDrvModExpCallBack,
+                                 callbackTag, pModExpOpData, pResult);
+
+       if (CPA_STATUS_SUCCESS != lacStatus) {
+               EPRINTK("%s(): Mod Exp Operation failed (%d).\n",
+                       __FUNCTION__, lacStatus);
+               krp->krp_status = ECANCELED;
+               icp_ocfDrvFreeFlatBuffer(pResult);
+               kmem_cache_free(drvLnModExp_zone, pModExpOpData);
+       }
+
+       return lacStatus;
+}
+
+/* Name        : icp_ocfDrvModExpCRT
+ *
+ * Description : This function will map ordinary Modular Exponentiation Chinese
+ * Remainder Theorem implementaion calls from OCF to the LAC API.
+ *
+ * Note : Mod Exp CRT for this driver is accelerated through LAC RSA type 2
+ * decrypt operation. Therefore P and Q input values must always be prime
+ * numbers. Although basic primality checks are done in LAC, it is up to the
+ * user to do any correct prime number checking before passing the inputs.
+ */
+
+static int icp_ocfDrvModExpCRT(struct cryptkop *krp)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+       CpaCyRsaDecryptOpData *rsaDecryptOpData = NULL;
+       void *callbackTag = NULL;
+       CpaFlatBuffer *pOutputData = NULL;
+
+       /*Parameter input checks are all done by LAC, no need to repeat
+          them here. */
+       callbackTag = krp;
+
+       rsaDecryptOpData = kmem_cache_zalloc(drvRSADecrypt_zone, GFP_KERNEL);
+       if (NULL == rsaDecryptOpData) {
+               APRINTK("%s():Failed to get memory"
+                       " for MOD EXP CRT Op data struct\n", __FUNCTION__);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       rsaDecryptOpData->pRecipientPrivateKey
+           = kmem_cache_zalloc(drvRSAPrivateKey_zone, GFP_KERNEL);
+       if (NULL == rsaDecryptOpData->pRecipientPrivateKey) {
+               APRINTK("%s():Failed to get memory for MOD EXP CRT"
+                       " private key values struct\n", __FUNCTION__);
+               kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       rsaDecryptOpData->pRecipientPrivateKey->
+           version = CPA_CY_RSA_VERSION_TWO_PRIME;
+       rsaDecryptOpData->pRecipientPrivateKey->
+           privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2;
+
+       pOutputData = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL);
+       if (NULL == pOutputData) {
+               APRINTK("%s():Failed to get memory"
+                       " for MOD EXP CRT output data\n", __FUNCTION__);
+               kmem_cache_free(drvRSAPrivateKey_zone,
+                               rsaDecryptOpData->pRecipientPrivateKey);
+               kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       rsaDecryptOpData->pRecipientPrivateKey->
+           version = CPA_CY_RSA_VERSION_TWO_PRIME;
+       rsaDecryptOpData->pRecipientPrivateKey->
+           privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2;
+
+       /* Link parameters */
+       rsaDecryptOpData->inputData.pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].crp_p;
+       BITS_TO_BYTES(rsaDecryptOpData->inputData.dataLenInBytes,
+                     krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(rsaDecryptOpData->inputData.pData,
+                           rsaDecryptOpData->inputData.dataLenInBytes);
+
+       rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime1P.pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].crp_p;
+       BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.
+                     prime1P.dataLenInBytes,
+                     krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.prime1P.pData,
+                           rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.prime1P.dataLenInBytes);
+
+       rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime2Q.pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].crp_p;
+       BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.
+                     prime2Q.dataLenInBytes,
+                     krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.prime2Q.pData,
+                           rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.prime2Q.dataLenInBytes);
+
+       rsaDecryptOpData->pRecipientPrivateKey->
+           privateKeyRep2.exponent1Dp.pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].crp_p;
+       BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.
+                     exponent1Dp.dataLenInBytes,
+                     krp->
+                     krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.exponent1Dp.pData,
+                           rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.exponent1Dp.dataLenInBytes);
+
+       rsaDecryptOpData->pRecipientPrivateKey->
+           privateKeyRep2.exponent2Dq.pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].crp_p;
+       BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->
+                     privateKeyRep2.exponent2Dq.dataLenInBytes,
+                     krp->
+                     krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.exponent2Dq.pData,
+                           rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.exponent2Dq.dataLenInBytes);
+
+       rsaDecryptOpData->pRecipientPrivateKey->
+           privateKeyRep2.coefficientQInv.pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].crp_p;
+       BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->
+                     privateKeyRep2.coefficientQInv.dataLenInBytes,
+                     krp->
+                     krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.coefficientQInv.pData,
+                           rsaDecryptOpData->pRecipientPrivateKey->
+                           privateKeyRep2.coefficientQInv.dataLenInBytes);
+
+       /* Output Parameter */
+       pOutputData->pData =
+           krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].crp_p;
+       BITS_TO_BYTES(pOutputData->dataLenInBytes,
+                     krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].
+                     crp_nbits);
+
+       lacStatus = cpaCyRsaDecrypt(CPA_INSTANCE_HANDLE_SINGLE,
+                                   icp_ocfDrvModExpCRTCallBack,
+                                   callbackTag, rsaDecryptOpData, pOutputData);
+
+       if (CPA_STATUS_SUCCESS != lacStatus) {
+               EPRINTK("%s(): Mod Exp CRT Operation failed (%d).\n",
+                       __FUNCTION__, lacStatus);
+               krp->krp_status = ECANCELED;
+               icp_ocfDrvFreeFlatBuffer(pOutputData);
+               kmem_cache_free(drvRSAPrivateKey_zone,
+                               rsaDecryptOpData->pRecipientPrivateKey);
+               kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData);
+       }
+
+       return lacStatus;
+}
+
+/* Name        : icp_ocfDrvCheckALessThanB
+ *
+ * Description : This function will check whether the first argument is less
+ * than the second. It is used to check whether the DSA RS sign Random K
+ * value is less than the Prime Q value (as defined in the specification)
+ *
+ */
+static int
+icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck)
+{
+
+       uint8_t *MSB_K = pK->pData;
+       uint8_t *MSB_Q = pQ->pData;
+       uint32_t buffer_lengths_in_bytes = pQ->dataLenInBytes;
+
+       if (DONT_RUN_LESS_THAN_CHECK == *doCheck) {
+               return FAIL_A_IS_GREATER_THAN_B;
+       }
+
+/*Check MSBs
+if A == B, check next MSB
+if A > B, return A_IS_GREATER_THAN_B
+if A < B, return A_IS_LESS_THAN_B (success)
+*/
+       while (*MSB_K == *MSB_Q) {
+               MSB_K++;
+               MSB_Q++;
+
+               buffer_lengths_in_bytes--;
+               if (0 == buffer_lengths_in_bytes) {
+                       DPRINTK("%s() Buffers have equal value!!\n",
+                               __FUNCTION__);
+                       return FAIL_A_IS_EQUAL_TO_B;
+               }
+
+       }
+
+       if (*MSB_K < *MSB_Q) {
+               return SUCCESS_A_IS_LESS_THAN_B;
+       } else {
+               return FAIL_A_IS_GREATER_THAN_B;
+       }
+
+}
+
+/* Name        : icp_ocfDrvDsaSign
+ *
+ * Description : This function will map DSA RS Sign from OCF to the LAC API.
+ *
+ * NOTE: From looking at OCF patch to OpenSSL and even the number of input
+ * parameters, OCF expects us to generate the random seed value. This value
+ * is generated and passed to LAC, however the number is discared in the
+ * callback and not returned to the user.
+ */
+static int icp_ocfDrvDsaSign(struct cryptkop *krp)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+       CpaCyDsaRSSignOpData *dsaRsSignOpData = NULL;
+       void *callbackTag = NULL;
+       CpaCyRandGenOpData randGenOpData;
+       int primeQSizeInBytes = 0;
+       int doCheck = 0;
+       CpaFlatBuffer randData;
+       CpaBoolean protocolStatus = CPA_FALSE;
+       CpaFlatBuffer *pR = NULL;
+       CpaFlatBuffer *pS = NULL;
+
+       callbackTag = krp;
+
+       BITS_TO_BYTES(primeQSizeInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].
+                     crp_nbits);
+
+       if (DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES != primeQSizeInBytes) {
+               APRINTK("%s(): DSA PRIME Q size not equal to the "
+                       "FIPS defined 20bytes, = %d\n",
+                       __FUNCTION__, primeQSizeInBytes);
+               krp->krp_status = EDOM;
+               return EDOM;
+       }
+
+       dsaRsSignOpData = kmem_cache_zalloc(drvDSARSSign_zone, GFP_KERNEL);
+       if (NULL == dsaRsSignOpData) {
+               APRINTK("%s():Failed to get memory"
+                       " for DSA RS Sign Op data struct\n", __FUNCTION__);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       dsaRsSignOpData->K.pData =
+           kmem_cache_alloc(drvDSARSSignKValue_zone, GFP_ATOMIC);
+
+       if (NULL == dsaRsSignOpData->K.pData) {
+               APRINTK("%s():Failed to get memory"
+                       " for DSA RS Sign Op Random value\n", __FUNCTION__);
+               kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       pR = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL);
+       if (NULL == pR) {
+               APRINTK("%s():Failed to get memory"
+                       " for DSA signature R\n", __FUNCTION__);
+               kmem_cache_free(drvDSARSSignKValue_zone,
+                               dsaRsSignOpData->K.pData);
+               kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       pS = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL);
+       if (NULL == pS) {
+               APRINTK("%s():Failed to get memory"
+                       " for DSA signature S\n", __FUNCTION__);
+               icp_ocfDrvFreeFlatBuffer(pR);
+               kmem_cache_free(drvDSARSSignKValue_zone,
+                               dsaRsSignOpData->K.pData);
+               kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       /*link prime number parameter for ease of processing */
+       dsaRsSignOpData->P.pData =
+           krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].crp_p;
+       BITS_TO_BYTES(dsaRsSignOpData->P.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(dsaRsSignOpData->P.pData,
+                           dsaRsSignOpData->P.dataLenInBytes);
+
+       dsaRsSignOpData->Q.pData =
+           krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].crp_p;
+       BITS_TO_BYTES(dsaRsSignOpData->Q.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].
+                     crp_nbits);
+
+       icp_ocfDrvSwapBytes(dsaRsSignOpData->Q.pData,
+                           dsaRsSignOpData->Q.dataLenInBytes);
+
+       /*generate random number with equal buffer size to Prime value Q,
+          but value less than Q */
+       dsaRsSignOpData->K.dataLenInBytes = dsaRsSignOpData->Q.dataLenInBytes;
+
+       randGenOpData.generateBits = CPA_TRUE;
+       randGenOpData.lenInBytes = dsaRsSignOpData->K.dataLenInBytes;
+
+       icp_ocfDrvPtrAndLenToFlatBuffer(dsaRsSignOpData->K.pData,
+                                       dsaRsSignOpData->K.dataLenInBytes,
+                                       &randData);
+
+       doCheck = 0;
+       while (icp_ocfDrvCheckALessThanB(&(dsaRsSignOpData->K),
+                                        &(dsaRsSignOpData->Q), &doCheck)) {
+
+               if (CPA_STATUS_SUCCESS
+                   != cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE,
+                                   NULL, NULL, &randGenOpData, &randData)) {
+                       APRINTK("%s(): ERROR - Failed to generate DSA RS Sign K"
+                               "value\n", __FUNCTION__);
+                       icp_ocfDrvFreeFlatBuffer(pS);
+                       icp_ocfDrvFreeFlatBuffer(pR);
+                       kmem_cache_free(drvDSARSSignKValue_zone,
+                                       dsaRsSignOpData->K.pData);
+                       kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData);
+                       krp->krp_status = EAGAIN;
+                       return EAGAIN;
+               }
+
+               doCheck++;
+               if (DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS == doCheck) {
+                       APRINTK("%s(): ERROR - Failed to find DSA RS Sign K "
+                               "value less than Q value\n", __FUNCTION__);
+                       icp_ocfDrvFreeFlatBuffer(pS);
+                       icp_ocfDrvFreeFlatBuffer(pR);
+                       kmem_cache_free(drvDSARSSignKValue_zone,
+                                       dsaRsSignOpData->K.pData);
+                       kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData);
+                       krp->krp_status = EAGAIN;
+                       return EAGAIN;
+               }
+
+       }
+       /*Rand Data - no need to swap bytes for pK */
+
+       /* Link parameters */
+       dsaRsSignOpData->G.pData =
+           krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_p;
+       BITS_TO_BYTES(dsaRsSignOpData->G.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_nbits);
+
+       icp_ocfDrvSwapBytes(dsaRsSignOpData->G.pData,
+                           dsaRsSignOpData->G.dataLenInBytes);
+
+       dsaRsSignOpData->X.pData =
+           krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_p;
+       BITS_TO_BYTES(dsaRsSignOpData->X.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_nbits);
+       icp_ocfDrvSwapBytes(dsaRsSignOpData->X.pData,
+                           dsaRsSignOpData->X.dataLenInBytes);
+
+       dsaRsSignOpData->M.pData =
+           krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].crp_p;
+       BITS_TO_BYTES(dsaRsSignOpData->M.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaRsSignOpData->M.pData,
+                           dsaRsSignOpData->M.dataLenInBytes);
+
+       /* Output Parameters */
+       pS->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].crp_p;
+       BITS_TO_BYTES(pS->dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].
+                     crp_nbits);
+
+       pR->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].crp_p;
+       BITS_TO_BYTES(pR->dataLenInBytes,
+                     krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].
+                     crp_nbits);
+
+       lacStatus = cpaCyDsaSignRS(CPA_INSTANCE_HANDLE_SINGLE,
+                                  icp_ocfDrvDsaRSSignCallBack,
+                                  callbackTag, dsaRsSignOpData,
+                                  &protocolStatus, pR, pS);
+
+       if (CPA_STATUS_SUCCESS != lacStatus) {
+               EPRINTK("%s(): DSA RS Sign Operation failed (%d).\n",
+                       __FUNCTION__, lacStatus);
+               krp->krp_status = ECANCELED;
+               icp_ocfDrvFreeFlatBuffer(pS);
+               icp_ocfDrvFreeFlatBuffer(pR);
+               kmem_cache_free(drvDSARSSignKValue_zone,
+                               dsaRsSignOpData->K.pData);
+               kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData);
+       }
+
+       return lacStatus;
+}
+
+/* Name        : icp_ocfDrvDsaVerify
+ *
+ * Description : This function will map DSA RS Verify from OCF to the LAC API.
+ *
+ */
+static int icp_ocfDrvDsaVerify(struct cryptkop *krp)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+       CpaCyDsaVerifyOpData *dsaVerifyOpData = NULL;
+       void *callbackTag = NULL;
+       CpaBoolean verifyStatus = CPA_FALSE;
+
+       callbackTag = krp;
+
+       dsaVerifyOpData = kmem_cache_zalloc(drvDSAVerify_zone, GFP_KERNEL);
+       if (NULL == dsaVerifyOpData) {
+               APRINTK("%s():Failed to get memory"
+                       " for DSA Verify Op data struct\n", __FUNCTION__);
+               krp->krp_status = ENOMEM;
+               return ENOMEM;
+       }
+
+       /* Link parameters */
+       dsaVerifyOpData->P.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->P.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->P.pData,
+                           dsaVerifyOpData->P.dataLenInBytes);
+
+       dsaVerifyOpData->Q.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->Q.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->Q.pData,
+                           dsaVerifyOpData->Q.dataLenInBytes);
+
+       dsaVerifyOpData->G.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->G.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->G.pData,
+                           dsaVerifyOpData->G.dataLenInBytes);
+
+       dsaVerifyOpData->Y.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->Y.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->Y.pData,
+                           dsaVerifyOpData->Y.dataLenInBytes);
+
+       dsaVerifyOpData->M.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->M.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->M.pData,
+                           dsaVerifyOpData->M.dataLenInBytes);
+
+       dsaVerifyOpData->R.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->R.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->R.pData,
+                           dsaVerifyOpData->R.dataLenInBytes);
+
+       dsaVerifyOpData->S.pData =
+           krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].crp_p;
+       BITS_TO_BYTES(dsaVerifyOpData->S.dataLenInBytes,
+                     krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].
+                     crp_nbits);
+       icp_ocfDrvSwapBytes(dsaVerifyOpData->S.pData,
+                           dsaVerifyOpData->S.dataLenInBytes);
+
+       lacStatus = cpaCyDsaVerify(CPA_INSTANCE_HANDLE_SINGLE,
+                                  icp_ocfDrvDsaVerifyCallBack,
+                                  callbackTag, dsaVerifyOpData, &verifyStatus);
+
+       if (CPA_STATUS_SUCCESS != lacStatus) {
+               EPRINTK("%s(): DSA Verify Operation failed (%d).\n",
+                       __FUNCTION__, lacStatus);
+               kmem_cache_free(drvDSAVerify_zone, dsaVerifyOpData);
+               krp->krp_status = ECANCELED;
+       }
+
+       return lacStatus;
+}
+
+/* Name        : icp_ocfDrvReadRandom
+ *
+ * Description : This function will map RNG functionality calls from OCF
+ * to the LAC API.
+ */
+int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords)
+{
+       CpaStatus lacStatus = CPA_STATUS_SUCCESS;
+       CpaCyRandGenOpData randGenOpData;
+       CpaFlatBuffer randData;
+
+       if (NULL == buf) {
+               APRINTK("%s(): Invalid input parameters\n", __FUNCTION__);
+               return EINVAL;
+       }
+
+       /* maxwords here is number of integers to generate data for */
+       randGenOpData.generateBits = CPA_TRUE;
+
+       randGenOpData.lenInBytes = maxwords * sizeof(uint32_t);
+
+       icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) buf,
+                                 &nb