[linux-yocto] [PATCH 1/1] Update cryptodev to latest version

Bruce Ashfield bruce.ashfield at windriver.com
Fri Sep 26 06:46:29 PDT 2014


On 14-09-23 01:14 AM, zhe.he at windriver.com wrote:
> From: He Zhe <zhe.he at windriver.com>
>
> Update cryptodev to latest version

thanks. I've done the update.

Bruce

>
> Signed-off-by: He Zhe <zhe.he at windriver.com>
> ---
>   .../crypto-import-cryptodev-linux-1.6.patch        | 4074 ++++++++++++++------
>   1 file changed, 2873 insertions(+), 1201 deletions(-)
>
> diff --git a/meta/cfg/kernel-cache/features/cryptodev/crypto-import-cryptodev-linux-1.6.patch b/meta/cfg/kernel-cache/features/cryptodev/crypto-import-cryptodev-linux-1.6.patch
> index dddddf2..18980f0 100644
> --- a/meta/cfg/kernel-cache/features/cryptodev/crypto-import-cryptodev-linux-1.6.patch
> +++ b/meta/cfg/kernel-cache/features/cryptodev/crypto-import-cryptodev-linux-1.6.patch
> @@ -1,42 +1,59 @@
> -From b65a074235f7a8f2a7e67554c25a968b210cb06a Mon Sep 17 00:00:00 2001
> -From: Bruce Ashfield <bruce.ashfield at windriver.com>
> -Date: Thu, 22 Aug 2013 00:20:38 -0400
> -Subject: [PATCH 1/2] crypto: import cryptodev-linux 1.6
> +From db8070c196429e6bc89b90643aab01801d1bebfd Mon Sep 17 00:00:00 2001
> +From: He Zhe <zhe.he at windriver.com>
> +Date: Mon, 22 Sep 2014 14:49:29 +0800
> +Subject: [PATCH] Add latest cryptodev 1.6
>
> -Adding crtypdev 1.6 support from:
> +Add cryptodev 1.6
> +Taken from:
> +https://github.com/cryptodev-linux/cryptodev-linux.git
> +6aa62a2c320b04f55fdfe0ed015c3d9b48997239
>
> -  http://download.gna.org/cryptodev-linux/cryptodev-linux-1.6.tar.gz
> -
> -to the kernel source tree as an integrated (versus out of tree) component.
> -
> -Signed-off-by: Bruce Ashfield <bruce.ashfield at windriver.com>
> +Signed-off-by: He Zhe <zhe.he at windriver.com>
>   ---
>    crypto/cryptodev/AUTHORS                  |   19 +
>    crypto/cryptodev/COPYING                  |  339 +++++++++
> - crypto/cryptodev/Makefile                 |   53 ++
> - crypto/cryptodev/NEWS                     |  153 ++++
> - crypto/cryptodev/README                   |   21 +
> - crypto/cryptodev/authenc.c                |  742 +++++++++++++++++++
> - crypto/cryptodev/cryptlib.c               |  377 ++++++++++
> - crypto/cryptodev/cryptlib.h               |   90 +++
> - crypto/cryptodev/crypto/cryptodev.h       |  292 ++++++++
> - crypto/cryptodev/cryptodev_int.h          |  134 ++++
> - crypto/cryptodev/ioctl.c                  | 1136 +++++++++++++++++++++++++++++
> - crypto/cryptodev/main.c                   |  257 +++++++
> + crypto/cryptodev/INSTALL                  |   32 +
> + crypto/cryptodev/Makefile                 |   72 ++
> + crypto/cryptodev/NEWS                     |  154 ++++
> + crypto/cryptodev/README                   |   40 +
> + crypto/cryptodev/authenc.c                |  758 +++++++++++++++++++
> + crypto/cryptodev/cryptlib.c               |  441 +++++++++++
> + crypto/cryptodev/cryptlib.h               |   93 +++
> + crypto/cryptodev/crypto/cryptodev.h       |  292 +++++++
> + crypto/cryptodev/cryptodev_int.h          |  145 ++++
> + crypto/cryptodev/examples/aes-gcm.c       |  139 ++++
> + crypto/cryptodev/examples/aes-gcm.h       |   28 +
> + crypto/cryptodev/examples/aes-sha1.c      |  139 ++++
> + crypto/cryptodev/examples/aes-sha1.h      |   31 +
> + crypto/cryptodev/examples/aes.c           |  242 ++++++
> + crypto/cryptodev/examples/aes.h           |   19 +
> + crypto/cryptodev/examples/sha.c           |  137 ++++
> + crypto/cryptodev/examples/sha.h           |   16 +
> + crypto/cryptodev/ioctl.c                  | 1169 +++++++++++++++++++++++++++++
> + crypto/cryptodev/lib/Makefile             |   15 +
> + crypto/cryptodev/lib/benchmark.c          |   88 +++
> + crypto/cryptodev/lib/benchmark.h          |   18 +
> + crypto/cryptodev/lib/combo.c              |  171 +++++
> + crypto/cryptodev/lib/hash.c               |  161 ++++
> + crypto/cryptodev/lib/hash.h               |   20 +
> + crypto/cryptodev/lib/main.c               |   28 +
> + crypto/cryptodev/lib/threshold.c          |   61 ++
> + crypto/cryptodev/lib/threshold.h          |   10 +
> + crypto/cryptodev/main.c                   |  267 +++++++
>    crypto/cryptodev/tests/Makefile           |   35 +
>    crypto/cryptodev/tests/async_cipher.c     |  338 +++++++++
>    crypto/cryptodev/tests/async_hmac.c       |  303 ++++++++
>    crypto/cryptodev/tests/async_speed.c      |  225 ++++++
> - crypto/cryptodev/tests/cipher-aead-srtp.c |  572 +++++++++++++++
> - crypto/cryptodev/tests/cipher-aead.c      |  574 +++++++++++++++
> - crypto/cryptodev/tests/cipher-gcm.c       |  529 ++++++++++++++
> - crypto/cryptodev/tests/cipher.c           |  326 +++++++++
> + crypto/cryptodev/tests/cipher-aead-srtp.c |  572 ++++++++++++++
> + crypto/cryptodev/tests/cipher-aead.c      |  574 ++++++++++++++
> + crypto/cryptodev/tests/cipher-gcm.c       |  529 +++++++++++++
> + crypto/cryptodev/tests/cipher.c           |  326 ++++++++
>    crypto/cryptodev/tests/cipher_comp.c      |  159 ++++
>    crypto/cryptodev/tests/fullspeed.c        |  184 +++++
>    crypto/cryptodev/tests/hash_comp.c        |  150 ++++
> - crypto/cryptodev/tests/hashcrypt_speed.c  |  206 ++++++
> + crypto/cryptodev/tests/hashcrypt_speed.c  |  206 +++++
>    crypto/cryptodev/tests/hmac.c             |  338 +++++++++
> - crypto/cryptodev/tests/hmac_comp.c        |  180 +++++
> + crypto/cryptodev/tests/hmac_comp.c        |  187 +++++
>    crypto/cryptodev/tests/openssl_wrapper.c  |  267 +++++++
>    crypto/cryptodev/tests/openssl_wrapper.h  |    6 +
>    crypto/cryptodev/tests/sha_speed.c        |  198 +++++
> @@ -45,11 +62,12 @@ Signed-off-by: Bruce Ashfield <bruce.ashfield at windriver.com>
>    crypto/cryptodev/util.c                   |   80 ++
>    crypto/cryptodev/util.h                   |    2 +
>    crypto/cryptodev/version.h                |    1 +
> - crypto/cryptodev/zc.c                     |  217 ++++++
> + crypto/cryptodev/zc.c                     |  208 +++++
>    crypto/cryptodev/zc.h                     |   27 +
> - 36 files changed, 8799 insertions(+)
> + 54 files changed, 10328 insertions(+)
>    create mode 100644 crypto/cryptodev/AUTHORS
>    create mode 100644 crypto/cryptodev/COPYING
> + create mode 100644 crypto/cryptodev/INSTALL
>    create mode 100644 crypto/cryptodev/Makefile
>    create mode 100644 crypto/cryptodev/NEWS
>    create mode 100644 crypto/cryptodev/README
> @@ -58,7 +76,24 @@ Signed-off-by: Bruce Ashfield <bruce.ashfield at windriver.com>
>    create mode 100644 crypto/cryptodev/cryptlib.h
>    create mode 100644 crypto/cryptodev/crypto/cryptodev.h
>    create mode 100644 crypto/cryptodev/cryptodev_int.h
> + create mode 100644 crypto/cryptodev/examples/aes-gcm.c
> + create mode 100644 crypto/cryptodev/examples/aes-gcm.h
> + create mode 100644 crypto/cryptodev/examples/aes-sha1.c
> + create mode 100644 crypto/cryptodev/examples/aes-sha1.h
> + create mode 100644 crypto/cryptodev/examples/aes.c
> + create mode 100644 crypto/cryptodev/examples/aes.h
> + create mode 100644 crypto/cryptodev/examples/sha.c
> + create mode 100644 crypto/cryptodev/examples/sha.h
>    create mode 100644 crypto/cryptodev/ioctl.c
> + create mode 100644 crypto/cryptodev/lib/Makefile
> + create mode 100644 crypto/cryptodev/lib/benchmark.c
> + create mode 100644 crypto/cryptodev/lib/benchmark.h
> + create mode 100644 crypto/cryptodev/lib/combo.c
> + create mode 100644 crypto/cryptodev/lib/hash.c
> + create mode 100644 crypto/cryptodev/lib/hash.h
> + create mode 100644 crypto/cryptodev/lib/main.c
> + create mode 100644 crypto/cryptodev/lib/threshold.c
> + create mode 100644 crypto/cryptodev/lib/threshold.h
>    create mode 100644 crypto/cryptodev/main.c
>    create mode 100644 crypto/cryptodev/tests/Makefile
>    create mode 100644 crypto/cryptodev/tests/async_cipher.c
> @@ -455,12 +490,50 @@ index 0000000..d159169
>   +consider it more useful to permit linking proprietary applications with the
>   +library.  If this is what you want to do, use the GNU Lesser General
>   +Public License instead of this License.
> +diff --git a/crypto/cryptodev/INSTALL b/crypto/cryptodev/INSTALL
> +new file mode 100644
> +index 0000000..2754c59
> +--- /dev/null
> ++++ b/crypto/cryptodev/INSTALL
> +@@ -0,0 +1,32 @@
> ++=== Installation instructions ===
> ++
> ++Simply run:
> ++$ make
> ++# make install
> ++
> ++The first command compiles the code and generates the kernel module
> ++and the latter installs the header files and the kernel module.
> ++
> ++After that you should set your system to load the kernel module on system
> ++load. In most systems this can be done as:
> ++# echo "cryptodev" >>/etc/modules
> ++
> ++or in systemd-enabled systems:
> ++# echo "cryptodev" > /etc/modules-load.d/cryptodev.conf
> ++
> ++=== Testing installation ===
> ++
> ++* cryptodev-linux:
> ++Check whether cryptodev-linux is operating as expected using the following
> ++command.
> ++$ make check
> ++
> ++* OpenSSL:
> ++run the following commands prior and after installation and compare.
> ++$ openssl speed -evp aes-128-cbc
> ++$ openssl speed -evp sha1
> ++
> ++* GnuTLS 3.x:
> ++run the following command prior and after installation and compare.
> ++$ gnutls-cli --benchmark-ciphers
> ++
>   diff --git a/crypto/cryptodev/Makefile b/crypto/cryptodev/Makefile
>   new file mode 100644
> -index 0000000..d66ef26
> +index 0000000..c657c70
>   --- /dev/null
>   +++ b/crypto/cryptodev/Makefile
> -@@ -0,0 +1,53 @@
> +@@ -0,0 +1,72 @@
>   +#
>   +# Since version 1.6 the asynchronous mode has been
>   +# disabled by default. To re-enable it uncomment the
> @@ -468,16 +541,24 @@ index 0000000..d66ef26
>   +#
>   +CRYPTODEV_CFLAGS ?= #-DENABLE_ASYNC
>   +KBUILD_CFLAGS += -I$(src) $(CRYPTODEV_CFLAGS)
> -+KERNEL_DIR = /lib/modules/$(shell uname -r)/build
> ++KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
>   +VERSION = 1.6
> -+PREFIX =
> ++PREFIX ?=
>   +
>   +cryptodev-objs = ioctl.o main.o cryptlib.o authenc.o zc.o util.o
>   +
>   +obj-m += cryptodev.o
>   +
> ++KERNEL_MAKE_OPTS := -C ${KERNEL_DIR} SUBDIRS=`pwd`
> ++ifneq (${ARCH},)
> ++KERNEL_MAKE_OPTS += ARCH=${ARCH}
> ++endif
> ++ifneq (${CROSS_COMPILE},)
> ++KERNEL_MAKE_OPTS += CROSS_COMPILE=${CROSS_COMPILE}
> ++endif
> ++
>   +build: version.h
> -+	make -C $(KERNEL_DIR) SUBDIRS=`pwd` modules
> ++	make ${KERNEL_MAKE_OPTS} modules
>   +
>   +version.h: Makefile
>   +	@echo "#define VERSION \"$(VERSION)\"" > version.h
> @@ -497,6 +578,17 @@ index 0000000..d66ef26
>   +check:
>   +	CFLAGS=$(CRYPTODEV_CFLAGS) KERNEL_DIR=$(KERNEL_DIR) make -C tests check
>   +
> ++CPOPTS =
> ++ifneq (${SHOW_TYPES},)
> ++CPOPTS += --show-types
> ++endif
> ++ifneq (${IGNORE_TYPES},)
> ++CPOPTS += --ignore ${IGNORE_TYPES}
> ++endif
> ++
> ++checkpatch:
> ++	$(KERNEL_DIR)/scripts/checkpatch.pl ${CPOPTS} --file *.c *.h
> ++
>   +FILEBASE = cryptodev-linux-$(VERSION)
>   +TMPDIR ?= /tmp
>   +OUTPUT = $(FILEBASE).tar.gz
> @@ -506,7 +598,7 @@ index 0000000..d66ef26
>   +	@rm -f *.tar.gz
>   +	@mkdir $(TMPDIR)/$(FILEBASE)
>   +	@cp -ar crypto extras tests examples Makefile *.c *.h README NEWS \
> -+		AUTHORS COPYING $(TMPDIR)/$(FILEBASE)
> ++		INSTALL AUTHORS COPYING $(TMPDIR)/$(FILEBASE)
>   +	@rm -rf $(TMPDIR)/$(FILEBASE)/.git* $(TMPDIR)/$(FILEBASE)/releases $(TMPDIR)/$(FILEBASE)/scripts
>   +	@tar -C /tmp -czf ./$(OUTPUT) $(FILEBASE)
>   +	@rm -rf $(TMPDIR)/$(FILEBASE)
> @@ -516,21 +608,32 @@ index 0000000..d66ef26
>   +	@mv $(OUTPUT) $(OUTPUT).sig releases/
>   diff --git a/crypto/cryptodev/NEWS b/crypto/cryptodev/NEWS
>   new file mode 100644
> -index 0000000..bd1b666
> +index 0000000..a0a7d38
>   --- /dev/null
>   +++ b/crypto/cryptodev/NEWS
> -@@ -0,0 +1,153 @@
> +@@ -0,0 +1,154 @@
> ++Version 1.7 (unreleased)
> ++
> ++* Added support for composite AEAD keys by Cristian Stoica.
> ++
> ++* Added support for sysctl to modify verbosity by Nikolaos Tsakalakis.
> ++
> ++* Several bugfixes by Cristian Stoica.
> ++
> ++* When a driver requires aligned data but unaligned are provided, then
> ++  zero copy is disabled to prevent driver failing to encrypt.
> ++
> ++
>   +Version 1.6 (released 2013-03-20)
>   +
>   +* Added modules_install target in Makefile
>   +
>   +* Added SHA224. Patch by Yashpal Dutta.
>   +
> -+* Asynchronous operations will not be scheduled if zero
> -+copy is disabled.
> ++* Asynchronous operations will not be scheduled if zero copy is disabled.
>   +
> -+* Asynchronous operations are disabled by default, unless
> -+-DENABLE_ASYNC is enabled on Makefile.
> ++* Asynchronous operations are disabled by default, unless -DENABLE_ASYNC
> ++  is enabled on Makefile.
>   +
>   +
>   +Version 1.5 (released 2012-08-04)
> @@ -539,8 +642,8 @@ index 0000000..bd1b666
>   +
>   +* Simplifications in memory locking. Patch by Phil Sutter.
>   +
> -+* Allow empty plaintext and authenticated data in AEAD
> -+ciphers. Patch by Jaren Johnston.
> ++* Allow empty plaintext and authenticated data in AEAD  ciphers.
> ++  Patch by Jaren Johnston.
>   +
>   +
>   +Version 1.4 (released 2012-03-15)
> @@ -550,11 +653,10 @@ index 0000000..bd1b666
>   +
>   +Version 1.3 (released 2012-02-29)
>   +
> -+* Return EBADMSG instead of ECANCELED on tag verification
> -+failure in authenc modes.
> ++* Return EBADMSG instead of ECANCELED on tag verification failure in
> ++  authenc modes.
>   +
> -+* COP_FLAG_RESET can be combined with COP_FLAG_UPDATE for
> -+efficiency.
> ++* COP_FLAG_RESET can be combined with COP_FLAG_UPDATE for efficiency.
>   +
>   +* Added more test cases.
>   +
> @@ -563,14 +665,12 @@ index 0000000..bd1b666
>   +
>   +Version 1.2 (released 2012-02-24)
>   +
> -+* In kernels that do not distinguish between hw
> -+accelerated ciphers or not set the SIOP_FLAG_KERNEL_DRIVER_ONLY
> -+flag based on driver name.
> ++* In kernels that do not distinguish between hw accelerated ciphers or
> ++  not set the SIOP_FLAG_KERNEL_DRIVER_ONLY flag based on driver name.
>   +
>   +* camelia was renamed to camellia.
>   +
> -+* Added COP_FLAG_RESET to allow resetting the state
> -+in multi-update.
> ++* Added COP_FLAG_RESET to allow resetting the state in multi-update.
>   +
>   +* Corrected issue in ARM processors with mv_cesa.
>   +
> @@ -581,20 +681,19 @@ index 0000000..bd1b666
>   +
>   +* Defined HASH_MAX_LEN in cryptodev.h
>   +
> -+* CIOCGSESSINFO ioctl() sets the SIOP_FLAG_KERNEL_DRIVER_ONLY
> -+flag if the driver is only available through kernel
> -+driver (and is not just software cipher).
> ++* CIOCGSESSINFO ioctl() sets the SIOP_FLAG_KERNEL_DRIVER_ONLY flag if the
> ++  driver is only available through kernel driver (and is not just software
> ++  cipher).
>   +
> -+* Added new encryption ioctl, CIOCAUTHCRYPT, which
> -+combines authentication and encryption. Operates
> -+in AEAD, TLS and SRTP modes (the API might change
> -+in later versions).
> ++* Added new encryption ioctl, CIOCAUTHCRYPT, which combines authentication
> ++  and encryption. Operates in AEAD, TLS and SRTP modes (the API might change
> ++  in later versions).
>   +
>   +
>   +Version 1.0 (released 2011-04-12)
>   +
> -+* Several fixes in the included examples. Based on
> -+patches by Vladimir Zapolskiy.
> ++* Several fixes in the included examples. Based on patches by Vladimir
> ++  Zapolskiy.
>   +
>   +
>   +Version 0.9 (released 2011-02-11)
> @@ -603,15 +702,13 @@ index 0000000..bd1b666
>   +  - sha_speed does performance testing of SHA1 and SHA256
>   +  - hashcrypt_speed additionally encrypts with AES128 and AES256
>   +
> -+* Allow updating the IV in userspace via the COP_FLAG_WRITE_IV
> -+flag.
> ++* Allow updating the IV in userspace via the COP_FLAG_WRITE_IV flag.
>   +
>   +* Export the alignmask in an OCF compatible way.
>   +
>   +* Fix for kernel crash on passing incorrect session ID.
>   +
> -+* Added CIOCGSESSINFO to export additional information
> -+for each session.
> ++* Added CIOCGSESSINFO to export additional information for each session.
>   +
>   +
>   +Version 0.8 (released 2010-11-06)
> @@ -626,39 +723,35 @@ index 0000000..bd1b666
>   +
>   +Version 0.7 (released 2010-10-08)
>   +
> -+* Added COP_FLAG_FINAL to make multi-update
> -+more efficient.
> ++* Added COP_FLAG_FINAL to make multi-update more efficient.
>   +
> -+* Added CRIOGET_NOT_NEEDED definition to allow
> -+users of the API to distinguish from the bare
> -+OpenBSD API that requires the CRIOGET.
> ++* Added CRIOGET_NOT_NEEDED definition to allow users of the API to
> ++  distinguish from the bare OpenBSD API that requires the CRIOGET.
>   +
>   +
>   +Version 0.6 (released 2010-09-16)
>   +
> -+* multi-update support for hash calculation using
> -+the new flag COP_FLAG_UPDATE.
> ++* multi-update support for hash calculation using the new flag
> ++  COP_FLAG_UPDATE.
>   +
>   +* Relicensed under GPLv2.
>   +
>   +* Added AES-CTR.
>   +
> -+* Corrected fallback to non-zero copy when referenced
> -+pages were not writable.
> ++* Corrected fallback to non-zero copy when referenced pages were
> ++  not writable.
>   +
>   +
>   +Version 0.5 (released 2010-07-06)
>   +
>   +* Corrected issue with zero copy on multiple pages.
>   +
> -+* Fallback to normal operation if user pages cannot be
> -+mapped.
> ++* Fallback to normal operation if user pages cannot be mapped.
>   +
>   +
>   +Version 0.4 (released 2010-07-03)
>   +
> -+* Internal engine supports operations with zero copy from
> -+user space.
> ++* Internal engine supports operations with zero copy from user space.
>   +
>   +
>   +Version 0.3 (released 2010-06-19)
> @@ -669,19 +762,19 @@ index 0000000..bd1b666
>   +Version 0.2 (released 2010-06-18)
>   +
>   +* Added compat_ioctl() to allow working on systems where userspace is 32bits
> -+and kernel is operating in 64bit mode (Phil Sutter)
> ++  and kernel is operating in 64bit mode (Phil Sutter)
>   +
>   +* Added several sanity checks to input.
>   +
>   diff --git a/crypto/cryptodev/README b/crypto/cryptodev/README
>   new file mode 100644
> -index 0000000..1176e70
> +index 0000000..eb19204
>   --- /dev/null
>   +++ b/crypto/cryptodev/README
> -@@ -0,0 +1,21 @@
> +@@ -0,0 +1,40 @@
>   +This is a /dev/crypto device driver, equivalent to those in OpenBSD or
>   +FreeBSD. The main idea is to access of existing ciphers in kernel space
> -+from userspace, thus enabling re-use of a hardware implementation of a
> ++from userspace, thus enabling the re-use of a hardware implementation of a
>   +cipher.
>   +
>   +For questions and suggestions please use the mailing lists at:
> @@ -697,15 +790,34 @@ index 0000000..1176e70
>   +
>   +* OpenSSL:
>   +
> -+The current releases of openssl support /dev/crypto by replacing
> -+eng_cryptodev.c with the version available in the extras subdirectory.
> -+In order to compile use the -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS flags.
> ++Note that OpenSSL's cryptodev implementation is outdated, and there
> ++are issues with it. For that we recommend to use the patches
> ++below, that we have provided to the openssl project.
> ++
> ++http://rt.openssl.org/Ticket/Display.html?id=2770&user=guest&pass=guest
> ++
> ++After applying the patches you can add cryptodev support by using the
> ++-DHAVE_CRYPTODEV and -DUSE_CRYPTODEV_DIGESTS flags during compilation.
> ++Note that the latter flag (digests) may induce a performance penalty
> ++in some systems.
> ++
> ++
> ++=== Modifying and viewing verbosity at runtime ===
> ++
> ++For debugging often the verbosity of the driver needs to be adjusted.
> ++The sysctl tool can be used for that.
> ++
> ++# sysctl ioctl.cryptodev_verbosity
> ++ioctl.cryptodev_verbosity = 0
> ++
> ++# sysctl ioctl.cryptodev_verbosity=3
> ++ioctl.cryptodev_verbosity = 3
>   diff --git a/crypto/cryptodev/authenc.c b/crypto/cryptodev/authenc.c
>   new file mode 100644
> -index 0000000..8bff677
> +index 0000000..1bd7377
>   --- /dev/null
>   +++ b/crypto/cryptodev/authenc.c
> -@@ -0,0 +1,742 @@
> +@@ -0,0 +1,758 @@
>   +/*
>   + * Driver for /dev/crypto device (aka CryptoDev)
>   + *
> @@ -771,12 +883,12 @@ index 0000000..8bff677
>   +
>   +	if (ses->alignmask) {
>   +		if (!IS_ALIGNED((unsigned long)caop->dst, ses->alignmask))
> -+			dprintk(2, KERN_WARNING, "careful - source address %lx is not %d byte aligned\n",
> -+				(unsigned long)caop->dst, ses->alignmask + 1);
> ++			dwarning(2, "careful - source address %p is not %d byte aligned",
> ++					caop->dst, ses->alignmask + 1);
>   +	}
>   +
>   +	if (kcaop->dst_len == 0) {
> -+		dprintk(1, KERN_WARNING, "Destination length cannot be zero\n");
> ++		dwarning(1, "Destination length cannot be zero");
>   +		return -EINVAL;
>   +	}
>   +
> @@ -792,8 +904,7 @@ index 0000000..8bff677
>   +	rc = __get_userbuf(caop->dst, kcaop->dst_len, 1, pagecount,
>   +	                   ses->pages, ses->sg, kcaop->task, kcaop->mm);
>   +	if (unlikely(rc)) {
> -+		dprintk(1, KERN_ERR,
> -+			"failed to get user pages for data input\n");
> ++		derr(1, "failed to get user pages for data input");
>   +		return -EINVAL;
>   +	}
>   +
> @@ -820,21 +931,21 @@ index 0000000..8bff677
>   +	int rc;
>   +
>   +	if (caop->dst == NULL && caop->auth_src == NULL) {
> -+		dprintk(1, KERN_ERR, "dst and auth_src cannot be both null\n");
> ++		derr(1, "dst and auth_src cannot be both null");
>   +		return -EINVAL;
>   +	}
>   +
>   +	if (ses->alignmask) {
>   +		if (!IS_ALIGNED((unsigned long)caop->dst, ses->alignmask))
> -+			dprintk(2, KERN_WARNING, "careful - source address %lx is not %d byte aligned\n",
> -+				(unsigned long)caop->dst, ses->alignmask + 1);
> ++			dwarning(2, "careful - source address %p is not %d byte aligned",
> ++					caop->dst, ses->alignmask + 1);
>   +		if (!IS_ALIGNED((unsigned long)caop->auth_src, ses->alignmask))
> -+			dprintk(2, KERN_WARNING, "careful - source address %lx is not %d byte aligned\n",
> -+				(unsigned long)caop->auth_src, ses->alignmask + 1);
> ++			dwarning(2, "careful - source address %p is not %d byte aligned",
> ++					caop->auth_src, ses->alignmask + 1);
>   +	}
>   +
>   +	if (unlikely(kcaop->dst_len == 0 || caop->auth_len == 0)) {
> -+		dprintk(1, KERN_WARNING, "Destination length cannot be zero\n");
> ++		dwarning(1, "Destination length cannot be zero");
>   +		return -EINVAL;
>   +	}
>   +
> @@ -844,7 +955,7 @@ index 0000000..8bff677
>   +	auth_pagecount = PAGECOUNT(caop->auth_src, caop->auth_len);
>   +	diff = (int)(caop->src - caop->auth_src);
>   +	if (diff > MAX_SRTP_AUTH_DATA_DIFF || diff < 0) {
> -+		dprintk(1, KERN_WARNING, "auth_src must overlap with src (diff: %d).\n", diff);
> ++		dwarning(1, "auth_src must overlap with src (diff: %d).", diff);
>   +		return -EINVAL;
>   +	}
>   +
> @@ -852,15 +963,14 @@ index 0000000..8bff677
>   +
>   +	rc = adjust_sg_array(ses, pagecount*2); /* double pages to have pages for dst(=auth_src) */
>   +	if (rc) {
> -+		dprintk(1, KERN_ERR, "cannot adjust sg array\n");
> ++		derr(1, "cannot adjust sg array");
>   +		return rc;
>   +	}
>   +
>   +	rc = __get_userbuf(caop->auth_src, caop->auth_len, 1, auth_pagecount,
>   +			   ses->pages, ses->sg, kcaop->task, kcaop->mm);
>   +	if (unlikely(rc)) {
> -+		dprintk(1, KERN_ERR,
> -+			"failed to get user pages for data input\n");
> ++		derr(1, "failed to get user pages for data input");
>   +		return -EINVAL;
>   +	}
>   +
> @@ -875,14 +985,49 @@ index 0000000..8bff677
>   +	(*dst_sg) = sg_advance(*dst_sg, diff);
>   +	if (*dst_sg == NULL) {
>   +		release_user_pages(ses);
> -+		dprintk(1, KERN_ERR,
> -+			"failed to get enough pages for auth data\n");
> ++		derr(1, "failed to get enough pages for auth data");
>   +		return -EINVAL;
>   +	}
>   +
>   +	return 0;
>   +}
>   +
> ++/*
> ++ * Return tag (digest) length for authenticated encryption
> ++ * If the cipher and digest are separate, hdata.init is set - just return
> ++ * digest length. Otherwise return digest length for aead ciphers
> ++ */
> ++static int cryptodev_get_tag_len(struct csession *ses_ptr)
> ++{
> ++	if (ses_ptr->hdata.init)
> ++		return ses_ptr->hdata.digestsize;
> ++	else
> ++		return cryptodev_cipher_get_tag_size(&ses_ptr->cdata);
> ++}
> ++
> ++/*
> ++ * Calculate destination buffer length for authenticated encryption. The
> ++ * expectation is that user-space code allocates exactly the same space for
> ++ * destination buffer before calling cryptodev. The result is cipher-dependent.
> ++ */
> ++static int cryptodev_get_dst_len(struct crypt_auth_op *caop, struct csession *ses_ptr)
> ++{
> ++	int dst_len = caop->len;
> ++	if (caop->op == COP_DECRYPT)
> ++		return dst_len;
> ++
> ++	dst_len += caop->tag_len;
> ++
> ++	/* for TLS always add some padding so the total length is rounded to
> ++	 * cipher block size */
> ++	if (caop->flags & COP_FLAG_AEAD_TLS_TYPE) {
> ++		int bs = ses_ptr->cdata.blocksize;
> ++		dst_len += bs - (dst_len % bs);
> ++	}
> ++
> ++	return dst_len;
> ++}
> ++
>   +static int fill_kcaop_from_caop(struct kernel_crypt_auth_op *kcaop, struct fcrypt *fcr)
>   +{
>   +	struct crypt_auth_op *caop = &kcaop->caop;
> @@ -892,38 +1037,31 @@ index 0000000..8bff677
>   +	/* this also enters ses_ptr->sem */
>   +	ses_ptr = crypto_get_session_by_sid(fcr, caop->ses);
>   +	if (unlikely(!ses_ptr)) {
> -+		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", caop->ses);
> ++		derr(1, "invalid session ID=0x%08X", caop->ses);
>   +		return -EINVAL;
>   +	}
>   +
>   +	if (caop->flags & COP_FLAG_AEAD_TLS_TYPE || caop->flags & COP_FLAG_AEAD_SRTP_TYPE) {
>   +		if (caop->src != caop->dst) {
> -+			dprintk(1, KERN_ERR,
> -+				"Non-inplace encryption and decryption is not efficient and not implemented\n");
> ++			derr(1, "Non-inplace encryption and decryption is not efficient and not implemented");
>   +			ret = -EINVAL;
>   +			goto out_unlock;
>   +		}
>   +	}
>   +
>   +	if (caop->tag_len == 0)
> -+		caop->tag_len = ses_ptr->hdata.digestsize;
> ++		caop->tag_len = cryptodev_get_tag_len(ses_ptr);
>   +
>   +	kcaop->ivlen = caop->iv ? ses_ptr->cdata.ivsize : 0;
> -+
> -+	if (caop->flags & COP_FLAG_AEAD_TLS_TYPE)
> -+		kcaop->dst_len = caop->len + ses_ptr->cdata.blocksize /* pad */ + caop->tag_len;
> -+	else
> -+		kcaop->dst_len = caop->len;
> -+
> ++	kcaop->dst_len = cryptodev_get_dst_len(caop, ses_ptr);
>   +	kcaop->task = current;
>   +	kcaop->mm = current->mm;
>   +
>   +	if (caop->iv) {
>   +		ret = copy_from_user(kcaop->iv, caop->iv, kcaop->ivlen);
>   +		if (unlikely(ret)) {
> -+			dprintk(1, KERN_ERR,
> -+				"error copying IV (%d bytes), copy_from_user returned %d for address %lx\n",
> -+				kcaop->ivlen, ret, (unsigned long)caop->iv);
> ++			derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p",
> ++					kcaop->ivlen, ret, caop->iv);
>   +			ret = -EFAULT;
>   +			goto out_unlock;
>   +		}
> @@ -947,7 +1085,7 @@ index 0000000..8bff677
>   +		ret = copy_to_user(kcaop->caop.iv,
>   +				kcaop->iv, kcaop->ivlen);
>   +		if (unlikely(ret)) {
> -+			dprintk(1, KERN_ERR, "Error in copying to userspace\n");
> ++			derr(1, "Error in copying to userspace");
>   +			return -EFAULT;
>   +		}
>   +	}
> @@ -959,7 +1097,7 @@ index 0000000..8bff677
>   +			struct fcrypt *fcr, void __user *arg)
>   +{
>   +	if (unlikely(copy_from_user(&kcaop->caop, arg, sizeof(kcaop->caop)))) {
> -+		dprintk(1, KERN_ERR, "Error in copying from userspace\n");
> ++		derr(1, "Error in copying from userspace");
>   +		return -EFAULT;
>   +	}
>   +
> @@ -973,61 +1111,61 @@ index 0000000..8bff677
>   +
>   +	ret = fill_caop_from_kcaop(kcaop, fcr);
>   +	if (unlikely(ret)) {
> -+		dprintk(1, KERN_ERR, "fill_caop_from_kcaop\n");
> ++		derr(1, "fill_caop_from_kcaop");
>   +		return ret;
>   +	}
>   +
>   +	if (unlikely(copy_to_user(arg, &kcaop->caop, sizeof(kcaop->caop)))) {
> -+		dprintk(1, KERN_ERR, "Error in copying to userspace\n");
> ++		derr(1, "Error in copying to userspace");
>   +		return -EFAULT;
>   +	}
>   +	return 0;
>   +}
>   +
> -+static void copy_tls_hash( struct scatterlist *dst_sg, int len, void* hash, int hash_len)
> ++static void copy_tls_hash(struct scatterlist *dst_sg, int len, void *hash, int hash_len)
>   +{
>   +	scatterwalk_map_and_copy(hash, dst_sg, len, hash_len, 1);
>   +}
>   +
> -+static void read_tls_hash( struct scatterlist *dst_sg, int len, void* hash, int hash_len)
> ++static void read_tls_hash(struct scatterlist *dst_sg, int len, void *hash, int hash_len)
>   +{
> -+	scatterwalk_map_and_copy(hash, dst_sg, len-hash_len, hash_len, 0);
> ++	scatterwalk_map_and_copy(hash, dst_sg, len - hash_len, hash_len, 0);
>   +}
>   +
> -+static int pad_record( struct scatterlist *dst_sg, int len, int block_size)
> ++static int pad_record(struct scatterlist *dst_sg, int len, int block_size)
>   +{
>   +	uint8_t pad[block_size];
>   +	int pad_size = block_size - (len % block_size);
>   +
> -+	memset(pad, pad_size-1, pad_size);
> ++	memset(pad, pad_size - 1, pad_size);
>   +
>   +	scatterwalk_map_and_copy(pad, dst_sg, len, pad_size, 1);
>   +
>   +	return pad_size;
>   +}
>   +
> -+static int verify_tls_record_pad( struct scatterlist *dst_sg, int len, int block_size)
> ++static int verify_tls_record_pad(struct scatterlist *dst_sg, int len, int block_size)
>   +{
>   +	uint8_t pad[256]; /* the maximum allowed */
>   +	uint8_t pad_size;
>   +	int i;
>   +
> -+	scatterwalk_map_and_copy(&pad_size, dst_sg, len-1, 1, 0);
> ++	scatterwalk_map_and_copy(&pad_size, dst_sg, len - 1, 1, 0);
>   +
> -+	if (pad_size+1 > len) {
> -+		dprintk(1, KERN_ERR, "Pad size: %d\n", pad_size);
> ++	if (pad_size + 1 > len) {
> ++		derr(1, "Pad size: %d", pad_size);
>   +		return -EBADMSG;
>   +	}
>   +
> -+	scatterwalk_map_and_copy(pad, dst_sg, len-pad_size-1, pad_size+1, 0);
> ++	scatterwalk_map_and_copy(pad, dst_sg, len - pad_size - 1, pad_size + 1, 0);
>   +
> -+	for (i=0;i<pad_size;i++)
> ++	for (i = 0; i < pad_size; i++)
>   +		if (pad[i] != pad_size) {
> -+			dprintk(1, KERN_ERR, "Pad size: %d, pad: %d\n", pad_size, (int)pad[i]);
> ++			derr(1, "Pad size: %u, pad: %d", pad_size, pad[i]);
>   +			return -EBADMSG;
>   +		}
>   +
> -+	return pad_size+1;
> ++	return pad_size + 1;
>   +}
>   +
>   +/* Authenticate and encrypt the TLS way (also perform padding).
> @@ -1051,7 +1189,7 @@ index 0000000..8bff677
>   +				ret = cryptodev_hash_update(&ses_ptr->hdata,
>   +								auth_sg, auth_len);
>   +				if (unlikely(ret)) {
> -+					dprintk(0, KERN_ERR, "cryptodev_hash_update: %d\n", ret);
> ++					derr(0, "cryptodev_hash_update: %d", ret);
>   +					return ret;
>   +				}
>   +			}
> @@ -1060,18 +1198,18 @@ index 0000000..8bff677
>   +				ret = cryptodev_hash_update(&ses_ptr->hdata,
>   +								dst_sg, len);
>   +				if (unlikely(ret)) {
> -+					dprintk(0, KERN_ERR, "cryptodev_hash_update: %d\n", ret);
> ++					derr(0, "cryptodev_hash_update: %d", ret);
>   +					return ret;
>   +				}
>   +			}
>   +
>   +			ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_hash_final: %d\n", ret);
> ++				derr(0, "cryptodev_hash_final: %d", ret);
>   +				return ret;
>   +			}
>   +
> -+			copy_tls_hash( dst_sg, len, hash_output, caop->tag_len);
> ++			copy_tls_hash(dst_sg, len, hash_output, caop->tag_len);
>   +			len += caop->tag_len;
>   +		}
>   +
> @@ -1084,7 +1222,7 @@ index 0000000..8bff677
>   +			ret = cryptodev_cipher_encrypt(&ses_ptr->cdata,
>   +							dst_sg, dst_sg, len);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_cipher_encrypt: %d\n", ret);
> ++				derr(0, "cryptodev_cipher_encrypt: %d", ret);
>   +				return ret;
>   +			}
>   +		}
> @@ -1094,14 +1232,14 @@ index 0000000..8bff677
>   +							dst_sg, dst_sg, len);
>   +
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_cipher_decrypt: %d\n", ret);
> ++				derr(0, "cryptodev_cipher_decrypt: %d", ret);
>   +				return ret;
>   +			}
>   +
>   +			if (ses_ptr->cdata.blocksize > 1) {
>   +				ret = verify_tls_record_pad(dst_sg, len, ses_ptr->cdata.blocksize);
>   +				if (unlikely(ret < 0)) {
> -+					dprintk(2, KERN_ERR, "verify_record_pad: %d\n", ret);
> ++					derr(2, "verify_record_pad: %d", ret);
>   +					fail = 1;
>   +				} else {
>   +					len -= ret;
> @@ -1111,18 +1249,18 @@ index 0000000..8bff677
>   +
>   +		if (ses_ptr->hdata.init != 0) {
>   +			if (unlikely(caop->tag_len > sizeof(vhash) || caop->tag_len > len)) {
> -+				dprintk(1, KERN_ERR, "Illegal tag len size\n");
> ++				derr(1, "Illegal tag len size");
>   +				return -EINVAL;
>   +			}
>   +
> -+			read_tls_hash( dst_sg, len, vhash, caop->tag_len);
> ++			read_tls_hash(dst_sg, len, vhash, caop->tag_len);
>   +			len -= caop->tag_len;
>   +
>   +			if (auth_len > 0) {
>   +				ret = cryptodev_hash_update(&ses_ptr->hdata,
>   +								auth_sg, auth_len);
>   +				if (unlikely(ret)) {
> -+					dprintk(0, KERN_ERR, "cryptodev_hash_update: %d\n", ret);
> ++					derr(0, "cryptodev_hash_update: %d", ret);
>   +					return ret;
>   +				}
>   +			}
> @@ -1131,19 +1269,19 @@ index 0000000..8bff677
>   +				ret = cryptodev_hash_update(&ses_ptr->hdata,
>   +									dst_sg, len);
>   +				if (unlikely(ret)) {
> -+					dprintk(0, KERN_ERR, "cryptodev_hash_update: %d\n", ret);
> ++					derr(0, "cryptodev_hash_update: %d", ret);
>   +					return ret;
>   +				}
>   +			}
>   +
>   +			ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_hash_final: %d\n", ret);
> ++				derr(0, "cryptodev_hash_final: %d", ret);
>   +				return ret;
>   +			}
>   +
>   +			if (memcmp(vhash, hash_output, caop->tag_len) != 0 || fail != 0) {
> -+				dprintk(2, KERN_ERR, "MAC verification failed (tag_len: %d)\n", caop->tag_len);
> ++				derr(2, "MAC verification failed (tag_len: %d)", caop->tag_len);
>   +				return -EBADMSG;
>   +			}
>   +		}
> @@ -1172,7 +1310,7 @@ index 0000000..8bff677
>   +			ret = cryptodev_cipher_encrypt(&ses_ptr->cdata,
>   +							dst_sg, dst_sg, len);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_cipher_encrypt: %d\n", ret);
> ++				derr(0, "cryptodev_cipher_encrypt: %d", ret);
>   +				return ret;
>   +			}
>   +		}
> @@ -1182,48 +1320,46 @@ index 0000000..8bff677
>   +				ret = cryptodev_hash_update(&ses_ptr->hdata,
>   +								auth_sg, auth_len);
>   +				if (unlikely(ret)) {
> -+					dprintk(0, KERN_ERR, "cryptodev_hash_update: %d\n", ret);
> ++					derr(0, "cryptodev_hash_update: %d", ret);
>   +					return ret;
>   +				}
>   +			}
>   +
>   +			ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_hash_final: %d\n", ret);
> ++				derr(0, "cryptodev_hash_final: %d", ret);
>   +				return ret;
>   +			}
>   +
> -+			if (unlikely(copy_to_user(caop->tag, hash_output, caop->tag_len))) {
> ++			if (unlikely(copy_to_user(caop->tag, hash_output, caop->tag_len)))
>   +				return -EFAULT;
> -+			}
>   +		}
>   +
>   +	} else {
>   +		if (ses_ptr->hdata.init != 0) {
>   +			if (unlikely(caop->tag_len > sizeof(vhash) || caop->tag_len > len)) {
> -+				dprintk(1, KERN_ERR, "Illegal tag len size\n");
> ++				derr(1, "Illegal tag len size");
>   +				return -EINVAL;
>   +			}
>   +
> -+			if (unlikely(copy_from_user(vhash, caop->tag, caop->tag_len))) {
> ++			if (unlikely(copy_from_user(vhash, caop->tag, caop->tag_len)))
>   +				return -EFAULT;
> -+			}
>   +
>   +			ret = cryptodev_hash_update(&ses_ptr->hdata,
>   +							auth_sg, auth_len);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_hash_update: %d\n", ret);
> ++				derr(0, "cryptodev_hash_update: %d", ret);
>   +				return ret;
>   +			}
>   +
>   +			ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_hash_final: %d\n", ret);
> ++				derr(0, "cryptodev_hash_final: %d", ret);
>   +				return ret;
>   +			}
>   +
>   +			if (memcmp(vhash, hash_output, caop->tag_len) != 0 || fail != 0) {
> -+				dprintk(2, KERN_ERR, "MAC verification failed\n");
> ++				derr(2, "MAC verification failed");
>   +				return -EBADMSG;
>   +			}
>   +		}
> @@ -1233,7 +1369,7 @@ index 0000000..8bff677
>   +							dst_sg, dst_sg, len);
>   +
>   +			if (unlikely(ret)) {
> -+				dprintk(0, KERN_ERR, "cryptodev_cipher_decrypt: %d\n", ret);
> ++				derr(0, "cryptodev_cipher_decrypt: %d", ret);
>   +				return ret;
>   +			}
>   +		}
> @@ -1258,7 +1394,7 @@ index 0000000..8bff677
>   +
>   +	max_tag_len = cryptodev_cipher_get_tag_size(&ses_ptr->cdata);
>   +	if (unlikely(caop->tag_len > max_tag_len)) {
> -+		dprintk(0, KERN_ERR, "Illegal tag length: %d\n", caop->tag_len);
> ++		derr(0, "Illegal tag length: %d", caop->tag_len);
>   +		return -EINVAL;
>   +	}
>   +
> @@ -1273,7 +1409,7 @@ index 0000000..8bff677
>   +		ret = cryptodev_cipher_encrypt(&ses_ptr->cdata,
>   +						src_sg, dst_sg, len);
>   +		if (unlikely(ret)) {
> -+			dprintk(0, KERN_ERR, "cryptodev_cipher_encrypt: %d\n", ret);
> ++			derr(0, "cryptodev_cipher_encrypt: %d", ret);
>   +			return ret;
>   +		}
>   +		kcaop->dst_len = len + caop->tag_len;
> @@ -1283,7 +1419,7 @@ index 0000000..8bff677
>   +						src_sg, dst_sg, len);
>   +
>   +		if (unlikely(ret)) {
> -+			dprintk(0, KERN_ERR, "cryptodev_cipher_decrypt: %d\n", ret);
> ++			derr(0, "cryptodev_cipher_decrypt: %d", ret);
>   +			return ret;
>   +		}
>   +		kcaop->dst_len = len - caop->tag_len;
> @@ -1303,15 +1439,15 @@ index 0000000..8bff677
>   +
>   +	if (caop->flags & COP_FLAG_AEAD_SRTP_TYPE) {
>   +		if (unlikely(ses_ptr->cdata.init != 0 &&
> -+			(ses_ptr->cdata.stream == 0 || ses_ptr->cdata.aead != 0)))
> -+		{
> -+			dprintk(0, KERN_ERR, "Only stream modes are allowed in SRTP mode (but not AEAD)\n");
> ++		             (ses_ptr->cdata.stream == 0 ||
> ++			      ses_ptr->cdata.aead != 0))) {
> ++			derr(0, "Only stream modes are allowed in SRTP mode (but not AEAD)");
>   +			return -EINVAL;
>   +		}
>   +
>   +		ret = get_userbuf_srtp(ses_ptr, kcaop, &auth_sg, &dst_sg);
>   +		if (unlikely(ret)) {
> -+			dprintk(1, KERN_ERR, "get_userbuf_srtp(): Error getting user pages.\n");
> ++			derr(1, "get_userbuf_srtp(): Error getting user pages.");
>   +			return ret;
>   +		}
>   +
> @@ -1323,23 +1459,23 @@ index 0000000..8bff677
>   +	          * so we just copy them to a free page, instead of trying
>   +	          * to map them.
>   +	          */
> -+		unsigned char* auth_buf = NULL;
> ++		unsigned char *auth_buf = NULL;
>   +		struct scatterlist tmp;
>   +
>   +		if (unlikely(caop->auth_len > PAGE_SIZE)) {
> -+			dprintk(1, KERN_ERR, "auth data len is excessive.\n");
> ++			derr(1, "auth data len is excessive.");
>   +			return -EINVAL;
>   +		}
>   +
>   +		auth_buf = (char *)__get_free_page(GFP_KERNEL);
>   +		if (unlikely(!auth_buf)) {
> -+			dprintk(1, KERN_ERR, "unable to get a free page.\n");
> ++			derr(1, "unable to get a free page.");
>   +			return -ENOMEM;
>   +		}
>   +
>   +		if (caop->auth_src && caop->auth_len > 0) {
>   +			if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) {
> -+				dprintk(1, KERN_ERR, "unable to copy auth data from userspace.\n");
> ++				derr(1, "unable to copy auth data from userspace.");
>   +				ret = -EFAULT;
>   +				goto free_auth_buf;
>   +			}
> @@ -1353,31 +1489,25 @@ index 0000000..8bff677
>   +		if (caop->flags & COP_FLAG_AEAD_TLS_TYPE && ses_ptr->cdata.aead == 0) {
>   +			ret = get_userbuf_tls(ses_ptr, kcaop, &dst_sg);
>   +			if (unlikely(ret)) {
> -+				dprintk(1, KERN_ERR, "get_userbuf_tls(): Error getting user pages.\n");
> ++				derr(1, "get_userbuf_tls(): Error getting user pages.");
>   +				goto free_auth_buf;
>   +			}
>   +
>   +			ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
>   +				   dst_sg, caop->len);
>   +		} else {
> -+			int dst_len;
> -+
>   +			if (unlikely(ses_ptr->cdata.init == 0 ||
> -+					ses_ptr->cdata.stream == 0 ||
> -+					ses_ptr->cdata.aead == 0))
> -+			{
> -+				dprintk(0, KERN_ERR, "Only stream and AEAD ciphers are allowed for authenc\n");
> ++			             (ses_ptr->cdata.stream == 0 &&
> ++				      ses_ptr->cdata.aead == 0))) {
> ++				derr(0, "Only stream and AEAD ciphers are allowed for authenc");
>   +				ret = -EINVAL;
>   +				goto free_auth_buf;
>   +			}
>   +
> -+			if (caop->op == COP_ENCRYPT) dst_len = caop->len + cryptodev_cipher_get_tag_size(&ses_ptr->cdata);
> -+			else dst_len = caop->len;
> -+
> -+			ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, dst_len,
> ++			ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, kcaop->dst_len,
>   +					  kcaop->task, kcaop->mm, &src_sg, &dst_sg);
>   +			if (unlikely(ret)) {
> -+				dprintk(1, KERN_ERR, "get_userbuf(): Error getting user pages.\n");
> ++				derr(1, "get_userbuf(): Error getting user pages.");
>   +				goto free_auth_buf;
>   +			}
>   +
> @@ -1402,19 +1532,19 @@ index 0000000..8bff677
>   +	int ret;
>   +
>   +	if (unlikely(caop->op != COP_ENCRYPT && caop->op != COP_DECRYPT)) {
> -+		dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", caop->op);
> ++		ddebug(1, "invalid operation op=%u", caop->op);
>   +		return -EINVAL;
>   +	}
>   +
>   +	/* this also enters ses_ptr->sem */
>   +	ses_ptr = crypto_get_session_by_sid(fcr, caop->ses);
>   +	if (unlikely(!ses_ptr)) {
> -+		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", caop->ses);
> ++		derr(1, "invalid session ID=0x%08X", caop->ses);
>   +		return -EINVAL;
>   +	}
>   +
>   +	if (unlikely(ses_ptr->cdata.init == 0)) {
> -+		dprintk(1, KERN_ERR, "cipher context not initialized\n");
> ++		derr(1, "cipher context not initialized");
>   +		ret = -EINVAL;
>   +		goto out_unlock;
>   +	}
> @@ -1423,8 +1553,7 @@ index 0000000..8bff677
>   +	if (ses_ptr->hdata.init != 0) {
>   +		ret = cryptodev_hash_reset(&ses_ptr->hdata);
>   +		if (unlikely(ret)) {
> -+			dprintk(1, KERN_ERR,
> -+				"error in cryptodev_hash_reset()\n");
> ++			derr(1, "error in cryptodev_hash_reset()");
>   +			goto out_unlock;
>   +		}
>   +	}
> @@ -1434,8 +1563,7 @@ index 0000000..8bff677
>   +
>   +	ret = __crypto_auth_run_zc(ses_ptr, kcaop);
>   +	if (unlikely(ret)) {
> -+		dprintk(1, KERN_ERR,
> -+			"error in __crypto_auth_run_zc()\n");
> ++		derr(1, "error in __crypto_auth_run_zc()");
>   +		goto out_unlock;
>   +	}
>   +
> @@ -1450,10 +1578,10 @@ index 0000000..8bff677
>   +}
>   diff --git a/crypto/cryptodev/cryptlib.c b/crypto/cryptodev/cryptlib.c
>   new file mode 100644
> -index 0000000..fad5ba6
> +index 0000000..44ce763
>   --- /dev/null
>   +++ b/crypto/cryptodev/cryptlib.c
> -@@ -0,0 +1,377 @@
> +@@ -0,0 +1,441 @@
>   +/*
>   + * Driver for /dev/crypto device (aka CryptoDev)
>   + *
> @@ -1490,6 +1618,8 @@ index 0000000..fad5ba6
>   +#include <crypto/hash.h>
>   +#include <crypto/cryptodev.h>
>   +#include <crypto/aead.h>
> ++#include <linux/rtnetlink.h>
> ++#include <crypto/authenc.h>
>   +#include "cryptodev_int.h"
>   +
>   +
> @@ -1509,19 +1639,89 @@ index 0000000..fad5ba6
>   +	complete(&res->completion);
>   +}
>   +
> ++int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
> ++		int aead)
> ++{
> ++	/*
> ++	 * For blockciphers (AES-CBC) or non-composite aead ciphers (like AES-GCM),
> ++	 * the key length is simply the cipher keylen obtained from userspace. If
> ++	 * the cipher is composite aead, the keylen is the sum of cipher keylen,
> ++	 * hmac keylen and a key header length. This key format is the one used in
> ++	 * Linux kernel for composite aead ciphers (crypto/authenc.c)
> ++	 */
> ++	unsigned int klen = sop->keylen;
> ++
> ++	if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN))
> ++		return -EINVAL;
> ++
> ++	if (aead && sop->mackeylen) {
> ++		if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN))
> ++			return -EINVAL;
> ++		klen += sop->mackeylen;
> ++		klen += RTA_SPACE(sizeof(struct crypto_authenc_key_param));
> ++	}
> ++
> ++	*keylen = klen;
> ++	return 0;
> ++}
> ++
> ++int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead)
> ++{
> ++	/*
> ++	 * Get cipher key from user-space. For blockciphers just copy it from
> ++	 * user-space. For composite aead ciphers combine it with the hmac key in
> ++	 * the format used by Linux kernel in crypto/authenc.c:
> ++	 *
> ++	 * [[AUTHENC_KEY_HEADER + CIPHER_KEYLEN] [AUTHENTICATION KEY] [CIPHER KEY]]
> ++	 */
> ++	struct crypto_authenc_key_param *param;
> ++	struct rtattr *rta;
> ++	int ret = 0;
> ++
> ++	if (aead && sop->mackeylen) {
> ++		/*
> ++		 * Composite aead ciphers. The first four bytes are the header type and
> ++		 * header length for aead keys
> ++		 */
> ++		rta = (void *)key;
> ++		rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
> ++		rta->rta_len = RTA_LENGTH(sizeof(*param));
> ++
> ++		/*
> ++		 * The next four bytes hold the length of the encryption key
> ++		 */
> ++		param = RTA_DATA(rta);
> ++		param->enckeylen = cpu_to_be32(sop->keylen);
> ++
> ++		/* Advance key pointer eight bytes and copy the hmac key */
> ++		key += RTA_SPACE(sizeof(*param));
> ++		if (unlikely(copy_from_user(key, sop->mackey, sop->mackeylen))) {
> ++			ret = -EFAULT;
> ++			goto error;
> ++		}
> ++		/* Advance key pointer past the hmac key */
> ++		key += sop->mackeylen;
> ++	}
> ++	/* now copy the blockcipher key */
> ++	if (unlikely(copy_from_user(key, sop->key, sop->keylen)))
> ++		ret = -EFAULT;
> ++
> ++error:
> ++	return ret;
> ++}
> ++
> ++
>   +int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
>   +				uint8_t *keyp, size_t keylen, int stream, int aead)
>   +{
>   +	int ret;
>   +
> -+	memset(out, 0, sizeof(*out));
> -+
>   +	if (aead == 0) {
>   +		struct ablkcipher_alg *alg;
>   +
>   +		out->async.s = crypto_alloc_ablkcipher(alg_name, 0, 0);
>   +		if (unlikely(IS_ERR(out->async.s))) {
> -+			dprintk(1, KERN_DEBUG, "Failed to load cipher %s\n", alg_name);
> ++			ddebug(1, "Failed to load cipher %s", alg_name);
>   +				return -EINVAL;
>   +		}
>   +
> @@ -1531,11 +1731,8 @@ index 0000000..fad5ba6
>   +			if (alg->max_keysize > 0 &&
>   +					unlikely((keylen < alg->min_keysize) ||
>   +					(keylen > alg->max_keysize))) {
> -+				dprintk(1, KERN_DEBUG,
> -+					"Wrong keylen '%zu' for algorithm '%s'. \
> -+					Use %u to %u.\n",
> -+					   keylen, alg_name, alg->min_keysize,
> -+					   alg->max_keysize);
> ++				ddebug(1, "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.",
> ++						keylen, alg_name, alg->min_keysize, alg->max_keysize);
>   +				ret = -EINVAL;
>   +				goto error;
>   +			}
> @@ -1549,7 +1746,7 @@ index 0000000..fad5ba6
>   +	} else {
>   +		out->async.as = crypto_alloc_aead(alg_name, 0, 0);
>   +		if (unlikely(IS_ERR(out->async.as))) {
> -+			dprintk(1, KERN_DEBUG, "Failed to load cipher %s\n", alg_name);
> ++			ddebug(1, "Failed to load cipher %s", alg_name);
>   +			return -EINVAL;
>   +		}
>   +
> @@ -1561,8 +1758,7 @@ index 0000000..fad5ba6
>   +	}
>   +
>   +	if (unlikely(ret)) {
> -+		dprintk(1, KERN_DEBUG, "Setting key failed for %s-%zu.\n",
> -+			alg_name, keylen*8);
> ++		ddebug(1, "Setting key failed for %s-%zu.", alg_name, keylen*8);
>   +		ret = -EINVAL;
>   +		goto error;
>   +	}
> @@ -1570,19 +1766,18 @@ index 0000000..fad5ba6
>   +	out->stream = stream;
>   +	out->aead = aead;
>   +
> -+	out->async.result = kmalloc(sizeof(*out->async.result), GFP_KERNEL);
> ++	out->async.result = kzalloc(sizeof(*out->async.result), GFP_KERNEL);
>   +	if (unlikely(!out->async.result)) {
>   +		ret = -ENOMEM;
>   +		goto error;
>   +	}
>   +
> -+	memset(out->async.result, 0, sizeof(*out->async.result));
>   +	init_completion(&out->async.result->completion);
>   +
>   +	if (aead == 0) {
>   +		out->async.request = ablkcipher_request_alloc(out->async.s, GFP_KERNEL);
>   +		if (unlikely(!out->async.request)) {
> -+			dprintk(1, KERN_ERR, "error allocating async crypto request\n");
> ++			derr(1, "error allocating async crypto request");
>   +			ret = -ENOMEM;
>   +			goto error;
>   +		}
> @@ -1593,7 +1788,7 @@ index 0000000..fad5ba6
>   +	} else {
>   +		out->async.arequest = aead_request_alloc(out->async.as, GFP_KERNEL);
>   +		if (unlikely(!out->async.arequest)) {
> -+			dprintk(1, KERN_ERR, "error allocating async crypto request\n");
> ++			derr(1, "error allocating async crypto request");
>   +			ret = -ENOMEM;
>   +			goto error;
>   +		}
> @@ -1614,7 +1809,7 @@ index 0000000..fad5ba6
>   +	} else {
>   +		if (out->async.arequest)
>   +			aead_request_free(out->async.arequest);
> -+		if (out->async.s)
> ++		if (out->async.as)
>   +			crypto_free_aead(out->async.as);
>   +	}
>   +	kfree(out->async.result);
> @@ -1657,8 +1852,7 @@ index 0000000..fad5ba6
>   +		 * another request. */
>   +
>   +		if (unlikely(cr->err)) {
> -+			dprintk(0, KERN_ERR, "error from async request: %d\n",
> -+				cr->err);
> ++			derr(0, "error from async request: %d", cr->err);
>   +			return cr->err;
>   +		}
>   +
> @@ -1676,7 +1870,7 @@ index 0000000..fad5ba6
>   +{
>   +	int ret;
>   +
> -+	INIT_COMPLETION(cdata->async.result->completion);
> ++	reinit_completion(&cdata->async.result->completion);
>   +
>   +	if (cdata->aead == 0) {
>   +		ablkcipher_request_set_crypt(cdata->async.request,
> @@ -1699,7 +1893,7 @@ index 0000000..fad5ba6
>   +{
>   +	int ret;
>   +
> -+	INIT_COMPLETION(cdata->async.result->completion);
> ++	reinit_completion(&cdata->async.result->completion);
>   +	if (cdata->aead == 0) {
>   +		ablkcipher_request_set_crypt(cdata->async.request,
>   +			(struct scatterlist *)src, dst,
> @@ -1724,7 +1918,7 @@ index 0000000..fad5ba6
>   +
>   +	hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0);
>   +	if (unlikely(IS_ERR(hdata->async.s))) {
> -+		dprintk(1, KERN_DEBUG, "Failed to load transform for %s\n", alg_name);
> ++		ddebug(1, "Failed to load transform for %s", alg_name);
>   +		return -EINVAL;
>   +	}
>   +
> @@ -1732,9 +1926,8 @@ index 0000000..fad5ba6
>   +	if (hmac_mode != 0) {
>   +		ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen);
>   +		if (unlikely(ret)) {
> -+			dprintk(1, KERN_DEBUG,
> -+				"Setting hmac key failed for %s-%zu.\n",
> -+				alg_name, mackeylen*8);
> ++			ddebug(1, "Setting hmac key failed for %s-%zu.",
> ++					alg_name, mackeylen*8);
>   +			ret = -EINVAL;
>   +			goto error;
>   +		}
> @@ -1743,18 +1936,17 @@ index 0000000..fad5ba6
>   +	hdata->digestsize = crypto_ahash_digestsize(hdata->async.s);
>   +	hdata->alignmask = crypto_ahash_alignmask(hdata->async.s);
>   +
> -+	hdata->async.result = kmalloc(sizeof(*hdata->async.result), GFP_KERNEL);
> ++	hdata->async.result = kzalloc(sizeof(*hdata->async.result), GFP_KERNEL);
>   +	if (unlikely(!hdata->async.result)) {
>   +		ret = -ENOMEM;
>   +		goto error;
>   +	}
>   +
> -+	memset(hdata->async.result, 0, sizeof(*hdata->async.result));
>   +	init_completion(&hdata->async.result->completion);
>   +
>   +	hdata->async.request = ahash_request_alloc(hdata->async.s, GFP_KERNEL);
>   +	if (unlikely(!hdata->async.request)) {
> -+		dprintk(0, KERN_ERR, "error allocating async crypto request\n");
> ++		derr(0, "error allocating async crypto request");
>   +		ret = -ENOMEM;
>   +		goto error;
>   +	}
> @@ -1765,7 +1957,7 @@ index 0000000..fad5ba6
>   +
>   +	ret = crypto_ahash_init(hdata->async.request);
>   +	if (unlikely(ret)) {
> -+		dprintk(0, KERN_ERR, "error in crypto_hash_init()\n");
> ++		derr(0, "error in crypto_hash_init()");
>   +		goto error_request;
>   +	}
>   +
> @@ -1798,7 +1990,7 @@ index 0000000..fad5ba6
>   +
>   +	ret = crypto_ahash_init(hdata->async.request);
>   +	if (unlikely(ret)) {
> -+		dprintk(0, KERN_ERR, "error in crypto_hash_init()\n");
> ++		derr(0, "error in crypto_hash_init()");
>   +		return ret;
>   +	}
>   +
> @@ -1811,7 +2003,7 @@ index 0000000..fad5ba6
>   +{
>   +	int ret;
>   +
> -+	INIT_COMPLETION(hdata->async.result->completion);
> ++	reinit_completion(&hdata->async.result->completion);
>   +	ahash_request_set_crypt(hdata->async.request, sg, NULL, len);
>   +
>   +	ret = crypto_ahash_update(hdata->async.request);
> @@ -1819,11 +2011,11 @@ index 0000000..fad5ba6
>   +	return waitfor(hdata->async.result, ret);
>   +}
>   +
> -+int cryptodev_hash_final(struct hash_data *hdata, void* output)
> ++int cryptodev_hash_final(struct hash_data *hdata, void *output)
>   +{
>   +	int ret;
>   +
> -+	INIT_COMPLETION(hdata->async.result->completion);
> ++	reinit_completion(&hdata->async.result->completion);
>   +	ahash_request_set_crypt(hdata->async.request, NULL, output, 0);
>   +
>   +	ret = crypto_ahash_final(hdata->async.request);
> @@ -1833,10 +2025,10 @@ index 0000000..fad5ba6
>   +
>   diff --git a/crypto/cryptodev/cryptlib.h b/crypto/cryptodev/cryptlib.h
>   new file mode 100644
> -index 0000000..1745d0f
> +index 0000000..a0a8a63
>   --- /dev/null
>   +++ b/crypto/cryptodev/cryptlib.h
> -@@ -0,0 +1,90 @@
> +@@ -0,0 +1,93 @@
>   +#ifndef CRYPTLIB_H
>   +# define CRYPTLIB_H
>   +
> @@ -1864,6 +2056,9 @@ index 0000000..1745d0f
>   +int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
>   +			  uint8_t *key, size_t keylen, int stream, int aead);
>   +void cryptodev_cipher_deinit(struct cipher_data *cdata);
> ++int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead);
> ++int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
> ++		int aead);
>   +ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata,
>   +			const struct scatterlist *sg1,
>   +			struct scatterlist *sg2, size_t len);
> @@ -1872,20 +2067,20 @@ index 0000000..1745d0f
>   +				struct scatterlist *sg2, size_t len);
>   +
>   +/* AEAD */
> -+inline static void cryptodev_cipher_auth(struct cipher_data *cdata,
> ++static inline void cryptodev_cipher_auth(struct cipher_data *cdata,
>   +					 struct scatterlist *sg1, size_t len)
>   +{
>   +	/* for some reason we _have_ to call that even for zero length sgs */
>   +	aead_request_set_assoc(cdata->async.arequest, len ? sg1 : NULL, len);
>   +}
>   +
> -+inline static void cryptodev_cipher_set_tag_size(struct cipher_data *cdata, int size)
> ++static inline void cryptodev_cipher_set_tag_size(struct cipher_data *cdata, int size)
>   +{
>   +	if (likely(cdata->aead != 0))
>   +		crypto_aead_setauthsize(cdata->async.as, size);
>   +}
>   +
> -+inline static int cryptodev_cipher_get_tag_size(struct cipher_data *cdata)
> ++static inline int cryptodev_cipher_get_tag_size(struct cipher_data *cdata)
>   +{
>   +	if (likely(cdata->init && cdata->aead != 0))
>   +		return crypto_aead_authsize(cdata->async.as);
> @@ -1893,13 +2088,13 @@ index 0000000..1745d0f
>   +		return 0;
>   +}
>   +
> -+inline static void cryptodev_cipher_set_iv(struct cipher_data *cdata,
> ++static inline void cryptodev_cipher_set_iv(struct cipher_data *cdata,
>   +				void *iv, size_t iv_size)
>   +{
>   +	memcpy(cdata->async.iv, iv, min(iv_size, sizeof(cdata->async.iv)));
>   +}
>   +
> -+inline static void cryptodev_cipher_get_iv(struct cipher_data *cdata,
> ++static inline void cryptodev_cipher_get_iv(struct cipher_data *cdata,
>   +				void *iv, size_t iv_size)
>   +{
>   +	memcpy(iv, cdata->async.iv, min(iv_size, sizeof(cdata->async.iv)));
> @@ -1929,7 +2124,7 @@ index 0000000..1745d0f
>   +#endif
>   diff --git a/crypto/cryptodev/crypto/cryptodev.h b/crypto/cryptodev/crypto/cryptodev.h
>   new file mode 100644
> -index 0000000..a2f11b1
> +index 0000000..7fb9c7d
>   --- /dev/null
>   +++ b/crypto/cryptodev/crypto/cryptodev.h
>   @@ -0,0 +1,292 @@
> @@ -2173,7 +2368,7 @@ index 0000000..a2f11b1
>   +
>   +/* input of CIOCKEY */
>   +struct crypt_kop {
> -+	__u32	crk_op;		/* cryptodev_crk_ot_t */
> ++	__u32	crk_op;		/* cryptodev_crk_op_t */
>   +	__u32	crk_status;
>   +	__u16	crk_iparams;
>   +	__u16	crk_oparams;
> @@ -2227,14 +2422,20 @@ index 0000000..a2f11b1
>   +#endif /* L_CRYPTODEV_H */
>   diff --git a/crypto/cryptodev/cryptodev_int.h b/crypto/cryptodev/cryptodev_int.h
>   new file mode 100644
> -index 0000000..12dd5b1
> +index 0000000..d7660fa
>   --- /dev/null
>   +++ b/crypto/cryptodev/cryptodev_int.h
> -@@ -0,0 +1,134 @@
> +@@ -0,0 +1,145 @@
>   +/* cipher stuff */
>   +#ifndef CRYPTODEV_INT_H
>   +# define CRYPTODEV_INT_H
>   +
> ++#include <linux/version.h>
> ++
> ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
> ++#  define reinit_completion(x) INIT_COMPLETION(*(x))
> ++#endif
> ++
>   +#include <linux/init.h>
>   +#include <linux/sched.h>
>   +#include <linux/fs.h>
> @@ -2251,11 +2452,16 @@ index 0000000..12dd5b1
>   +#define dprintk(level, severity, format, a...)			\
>   +	do {							\
>   +		if (level <= cryptodev_verbosity)		\
> -+			printk(severity PFX "%s[%u] (%s:%u): " format,	\
> ++			printk(severity PFX "%s[%u] (%s:%u): " format "\n",	\
>   +			       current->comm, current->pid,	\
>   +			       __func__, __LINE__,		\
>   +			       ##a);				\
>   +	} while (0)
> ++#define derr(level, format, a...) dprintk(level, KERN_ERR, format, ##a)
> ++#define dwarning(level, format, a...) dprintk(level, KERN_WARNING, format, ##a)
> ++#define dinfo(level, format, a...) dprintk(level, KERN_INFO, format, ##a)
> ++#define ddebug(level, format, a...) dprintk(level, KERN_DEBUG, format, ##a)
> ++
>   +
>   +extern int cryptodev_verbosity;
>   +
> @@ -2284,7 +2490,7 @@ index 0000000..12dd5b1
>   +};
>   +
>   +/* input of CIOCCRYPT */
> -+ struct compat_crypt_op {
> ++struct compat_crypt_op {
>   +	uint32_t	ses;		/* session identifier */
>   +	uint16_t	op;		/* COP_ENCRYPT or COP_DECRYPT */
>   +	uint16_t	flags;		/* see COP_FLAG_* */
> @@ -2358,686 +2564,1500 @@ index 0000000..12dd5b1
>   +
>   +struct csession *crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid);
>   +
> -+inline static void crypto_put_session(struct csession * ses_ptr)
> ++static inline void crypto_put_session(struct csession *ses_ptr)
>   +{
>   +	mutex_unlock(&ses_ptr->sem);
>   +}
> -+int adjust_sg_array(struct csession * ses, int pagecount);
> ++int adjust_sg_array(struct csession *ses, int pagecount);
>   +
>   +#endif /* CRYPTODEV_INT_H */
> -diff --git a/crypto/cryptodev/ioctl.c b/crypto/cryptodev/ioctl.c
> +diff --git a/crypto/cryptodev/examples/aes-gcm.c b/crypto/cryptodev/examples/aes-gcm.c
>   new file mode 100644
> -index 0000000..f26cf93
> +index 0000000..6791f4e
>   --- /dev/null
> -+++ b/crypto/cryptodev/ioctl.c
> -@@ -0,0 +1,1136 @@
> -+/*
> -+ * Driver for /dev/crypto device (aka CryptoDev)
> -+ *
> -+ * Copyright (c) 2004 Michal Ludvig <mludvig at logix.net.nz>, SuSE Labs
> -+ * Copyright (c) 2009,2010,2011 Nikos Mavrogiannopoulos <nmav at gnutls.org>
> -+ * Copyright (c) 2010 Phil Sutter
> -+ *
> -+ * This file is part of linux cryptodev.
> -+ *
> -+ * This program is free software; you can redistribute it and/or
> -+ * modify it under the terms of the GNU General Public License
> -+ * as published by the Free Software Foundation; either version 2
> -+ * of the License, or (at your option) any later version.
> -+ *
> -+ * 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
> -+ */
> -+
> ++++ b/crypto/cryptodev/examples/aes-gcm.c
> +@@ -0,0 +1,139 @@
>   +/*
> -+ * Device /dev/crypto provides an interface for
> -+ * accessing kernel CryptoAPI algorithms (ciphers,
> -+ * hashes) from userspace programs.
> ++ * Demo on how to use /dev/crypto device for ciphering.
>   + *
> -+ * /dev/crypto interface was originally introduced in
> -+ * OpenBSD and this module attempts to keep the API.
> ++ * Placed under public domain.
>   + *
>   + */
> -+
> -+#include <crypto/hash.h>
> -+#include <linux/crypto.h>
> -+#include <linux/mm.h>
> -+#include <linux/highmem.h>
> -+#include <linux/ioctl.h>
> -+#include <linux/random.h>
> -+#include <linux/syscalls.h>
> -+#include <linux/pagemap.h>
> -+#include <linux/poll.h>
> -+#include <linux/uaccess.h>
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
>   +#include <crypto/cryptodev.h>
> -+#include <linux/scatterlist.h>
> -+#include "cryptodev_int.h"
> -+#include "zc.h"
> -+#include "version.h"
> ++#include "aes-gcm.h"
>   +
> -+MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav at gnutls.org>");
> -+MODULE_DESCRIPTION("CryptoDev driver");
> -+MODULE_LICENSE("GPL");
> ++int aes_gcm_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size)
> ++{
> ++#ifdef CIOCGSESSINFO
> ++	struct session_info_op siop;
> ++#endif
>   +
> -+/* ====== Compile-time config ====== */
> ++	memset(ctx, 0, sizeof(*ctx));
> ++	ctx->cfd = cfd;
>   +
> -+/* Default (pre-allocated) and maximum size of the job queue.
> -+ * These are free, pending and done items all together. */
> -+#define DEF_COP_RINGSIZE 16
> -+#define MAX_COP_RINGSIZE 64
> ++	ctx->sess.cipher = CRYPTO_AES_GCM;
> ++	ctx->sess.keylen = key_size;
> ++	ctx->sess.key = (void*)key;
> ++	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
> ++		perror("ioctl(CIOCGSESSION)");
> ++		return -1;
> ++	}
>   +
> -+/* ====== Module parameters ====== */
> ++#ifdef CIOCGSESSINFO
> ++	siop.ses = ctx->sess.ses;
> ++	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
> ++		perror("ioctl(CIOCGSESSINFO)");
> ++		return -1;
> ++	}
> ++	printf("Got %s with driver %s\n",
> ++			siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
> ++	if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
> ++		printf("Note: This is not an accelerated cipher\n");
> ++	}
> ++	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */
> ++	ctx->alignmask = siop.alignmask;
> ++#endif
> ++	return 0;
> ++}
>   +
> -+int cryptodev_verbosity;
> -+module_param(cryptodev_verbosity, int, 0644);
> -+MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
> ++void aes_gcm_ctx_deinit(struct cryptodev_ctx* ctx)
> ++{
> ++	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
> ++		perror("ioctl(CIOCFSESSION)");
> ++	}
> ++}
>   +
> -+/* ====== CryptoAPI ====== */
> -+struct todo_list_item {
> -+	struct list_head __hook;
> -+	struct kernel_crypt_op kcop;
> -+	int result;
> -+};
> ++int
> ++aes_gcm_encrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	const void* plaintext, void* ciphertext, size_t size)
> ++{
> ++	struct crypt_auth_op cryp;
> ++	void* p;
> ++	
> ++	/* check plaintext and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (plaintext != p) {
> ++			fprintf(stderr, "plaintext is not aligned\n");
> ++			return -1;
> ++		}
>   +
> -+struct locked_list {
> -+	struct list_head list;
> -+	struct mutex lock;
> -+};
> ++		p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (ciphertext != p) {
> ++			fprintf(stderr, "ciphertext is not aligned\n");
> ++			return -1;
> ++		}
> ++	}
>   +
> -+struct crypt_priv {
> -+	struct fcrypt fcrypt;
> -+	struct locked_list free, todo, done;
> -+	int itemcount;
> -+	struct work_struct cryptask;
> -+	wait_queue_head_t user_waiter;
> -+};
> ++	memset(&cryp, 0, sizeof(cryp));
>   +
> -+#define FILL_SG(sg, ptr, len)					\
> -+	do {							\
> -+		(sg)->page = virt_to_page(ptr);			\
> -+		(sg)->offset = offset_in_page(ptr);		\
> -+		(sg)->length = len;				\
> -+		(sg)->dma_address = 0;				\
> -+	} while (0)
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.iv = (void*)iv;
> ++	cryp.op = COP_ENCRYPT;
> ++	cryp.auth_len = auth_size;
> ++	cryp.auth_src = (void*)auth;
> ++	cryp.len = size;
> ++	cryp.src = (void*)plaintext;
> ++	cryp.dst = ciphertext;
> ++	if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCAUTHCRYPT)");
> ++		return -1;
> ++	}
>   +
> -+/* cryptodev's own workqueue, keeps crypto tasks from disturbing the force */
> -+static struct workqueue_struct *cryptodev_wq;
> ++	return 0;
> ++}
>   +
> -+/* Prepare session for future use. */
> -+static int
> -+crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
> ++int
> ++aes_gcm_decrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	const void* ciphertext, void* plaintext, size_t size)
>   +{
> -+	struct csession	*ses_new = NULL, *ses_ptr;
> -+	int ret = 0;
> -+	const char *alg_name = NULL;
> -+	const char *hash_name = NULL;
> -+	int hmac_mode = 1, stream = 0, aead = 0;
> ++	struct crypt_auth_op cryp;
> ++	void* p;
> ++	
> ++	/* check plaintext and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (plaintext != p) {
> ++			fprintf(stderr, "plaintext is not aligned\n");
> ++			return -1;
> ++		}
>   +
> -+	/* Does the request make sense? */
> -+	if (unlikely(!sop->cipher && !sop->mac)) {
> -+		dprintk(1, KERN_DEBUG, "Both 'cipher' and 'mac' unset.\n");
> -+		return -EINVAL;
> ++		p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (ciphertext != p) {
> ++			fprintf(stderr, "ciphertext is not aligned\n");
> ++			return -1;
> ++		}
>   +	}
>   +
> -+	switch (sop->cipher) {
> -+	case 0:
> -+		break;
> -+	case CRYPTO_DES_CBC:
> -+		alg_name = "cbc(des)";
> -+		break;
> -+	case CRYPTO_3DES_CBC:
> -+		alg_name = "cbc(des3_ede)";
> -+		break;
> -+	case CRYPTO_BLF_CBC:
> -+		alg_name = "cbc(blowfish)";
> -+		break;
> -+	case CRYPTO_AES_CBC:
> -+		alg_name = "cbc(aes)";
> -+		break;
> -+	case CRYPTO_AES_ECB:
> -+		alg_name = "ecb(aes)";
> -+		break;
> -+	case CRYPTO_CAMELLIA_CBC:
> -+		alg_name = "cbc(camellia)";
> -+		break;
> -+	case CRYPTO_AES_CTR:
> -+		alg_name = "ctr(aes)";
> -+		stream = 1;
> -+		break;
> -+	case CRYPTO_AES_GCM:
> -+		alg_name = "gcm(aes)";
> -+		stream = 1;
> -+		aead = 1;
> -+		break;
> -+	case CRYPTO_NULL:
> -+		alg_name = "ecb(cipher_null)";
> -+		stream = 1;
> -+		break;
> -+	default:
> -+		dprintk(1, KERN_DEBUG, "bad cipher: %d\n", sop->cipher);
> -+		return -EINVAL;
> ++	memset(&cryp, 0, sizeof(cryp));
> ++
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.iv = (void*)iv;
> ++	cryp.op = COP_DECRYPT;
> ++	cryp.auth_len = auth_size;
> ++	cryp.auth_src = (void*)auth;
> ++	cryp.len = size;
> ++	cryp.src = (void*)ciphertext;
> ++	cryp.dst = plaintext;
> ++	if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCAUTHCRYPT)");
> ++		return -1;
>   +	}
>   +
> -+	switch (sop->mac) {
> -+	case 0:
> -+		break;
> -+	case CRYPTO_MD5_HMAC:
> -+		hash_name = "hmac(md5)";
> -+		break;
> -+	case CRYPTO_RIPEMD160_HMAC:
> -+		hash_name = "hmac(rmd160)";
> -+		break;
> -+	case CRYPTO_SHA1_HMAC:
> -+		hash_name = "hmac(sha1)";
> -+		break;
> -+	case CRYPTO_SHA2_224_HMAC:
> -+		hash_name = "hmac(sha224)";
> -+		break;
> ++	return 0;
> ++}
>   +
> -+	case CRYPTO_SHA2_256_HMAC:
> -+		hash_name = "hmac(sha256)";
> -+		break;
> -+	case CRYPTO_SHA2_384_HMAC:
> -+		hash_name = "hmac(sha384)";
> -+		break;
> -+	case CRYPTO_SHA2_512_HMAC:
> -+		hash_name = "hmac(sha512)";
> -+		break;
> +diff --git a/crypto/cryptodev/examples/aes-gcm.h b/crypto/cryptodev/examples/aes-gcm.h
> +new file mode 100644
> +index 0000000..1ddc5fe
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/aes-gcm.h
> +@@ -0,0 +1,28 @@
> ++#ifndef AES_H
> ++# define AES_H
>   +
> -+	/* non-hmac cases */
> -+	case CRYPTO_MD5:
> -+		hash_name = "md5";
> -+		hmac_mode = 0;
> -+		break;
> -+	case CRYPTO_RIPEMD160:
> -+		hash_name = "rmd160";
> -+		hmac_mode = 0;
> -+		break;
> -+	case CRYPTO_SHA1:
> -+		hash_name = "sha1";
> -+		hmac_mode = 0;
> -+		break;
> -+	case CRYPTO_SHA2_224:
> -+		hash_name = "sha224";
> -+		hmac_mode = 0;
> -+		break;
> -+	case CRYPTO_SHA2_256:
> -+		hash_name = "sha256";
> -+		hmac_mode = 0;
> -+		break;
> -+	case CRYPTO_SHA2_384:
> -+		hash_name = "sha384";
> -+		hmac_mode = 0;
> -+		break;
> -+	case CRYPTO_SHA2_512:
> -+		hash_name = "sha512";
> -+		hmac_mode = 0;
> -+		break;
> -+	default:
> -+		dprintk(1, KERN_DEBUG, "bad mac: %d\n", sop->mac);
> -+		return -EINVAL;
> -+	}
> ++#include <stdint.h>
>   +
> -+	/* Create a session and put it to the list. */
> -+	ses_new = kzalloc(sizeof(*ses_new), GFP_KERNEL);
> -+	if (!ses_new)
> -+		return -ENOMEM;
> ++struct cryptodev_ctx {
> ++	int cfd;
> ++	struct session_op sess;
> ++	uint16_t alignmask;
> ++};
>   +
> -+	/* Set-up crypto transform. */
> -+	if (alg_name) {
> -+		uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
> ++#define	AES_BLOCK_SIZE	16
>   +
> -+		if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
> -+			dprintk(1, KERN_DEBUG,
> -+				"Setting key failed for %s-%zu.\n",
> -+				alg_name, (size_t)sop->keylen*8);
> -+			ret = -EINVAL;
> -+			goto error_cipher;
> -+		}
> ++int aes_gcm_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size);
> ++void aes_gcm_ctx_deinit();
>   +
> -+		if (unlikely(copy_from_user(keyp, sop->key, sop->keylen))) {
> -+			ret = -EFAULT;
> -+			goto error_cipher;
> -+		}
> ++/* Note that encryption assumes that ciphertext has enough size
> ++ * for the tag to be appended. In decryption the tag is assumed
> ++ * to be the last bytes of ciphertext.
> ++ */
> ++int aes_gcm_encrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	const void* plaintext, void* ciphertext, size_t size);
> ++int aes_gcm_decrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	const void* ciphertext, void* plaintext, size_t size);
>   +
> -+		ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keyp,
> -+						sop->keylen, stream, aead);
> -+		if (ret < 0) {
> -+			dprintk(1, KERN_DEBUG,
> -+				"Failed to load cipher for %s\n", alg_name);
> -+			ret = -EINVAL;
> -+			goto error_cipher;
> -+		}
> -+	}
> ++#endif
> +diff --git a/crypto/cryptodev/examples/aes-sha1.c b/crypto/cryptodev/examples/aes-sha1.c
> +new file mode 100644
> +index 0000000..e93e3c4
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/aes-sha1.c
> +@@ -0,0 +1,139 @@
> ++/*
> ++ * Demo on how to use /dev/crypto device for ciphering.
> ++ *
> ++ * Placed under public domain.
> ++ *
> ++ */
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include "aes-sha1.h"
>   +
> -+	if (hash_name && aead == 0) {
> -+		uint8_t keyp[CRYPTO_HMAC_MAX_KEY_LEN];
> ++/* This is the TLS version of AES-CBC with HMAC-SHA1.
> ++ */
>   +
> -+		if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
> -+			dprintk(1, KERN_DEBUG,
> -+				"Setting key failed for %s-%zu.\n",
> -+				alg_name, (size_t)sop->mackeylen*8);
> -+			ret = -EINVAL;
> -+			goto error_hash;
> -+		}
> ++int aes_sha1_ctx_init(struct cryptodev_ctx* ctx, int cfd,
> ++	const uint8_t *key, unsigned int key_size,
> ++	const uint8_t *mac_key, unsigned int mac_key_size)
> ++{
> ++#ifdef CIOCGSESSINFO
> ++	struct session_info_op siop;
> ++#endif
>   +
> -+		if (sop->mackey && unlikely(copy_from_user(keyp, sop->mackey,
> -+					    sop->mackeylen))) {
> -+			ret = -EFAULT;
> -+			goto error_hash;
> -+		}
> ++	memset(ctx, 0, sizeof(*ctx));
> ++	ctx->cfd = cfd;
>   +
> -+		ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode,
> -+							keyp, sop->mackeylen);
> -+		if (ret != 0) {
> -+			dprintk(1, KERN_DEBUG, "Failed to load hash for %s\n", hash_name);
> -+			ret = -EINVAL;
> -+			goto error_hash;
> -+		}
> -+	}
> ++	ctx->sess.cipher = CRYPTO_AES_CBC;
> ++	ctx->sess.keylen = key_size;
> ++	ctx->sess.key = (void*)key;
>   +
> -+	ses_new->alignmask = max(ses_new->cdata.alignmask,
> -+	                                          ses_new->hdata.alignmask);
> -+	dprintk(2, KERN_DEBUG, "got alignmask %d\n", ses_new->alignmask);
> ++	ctx->sess.mac = CRYPTO_SHA1_HMAC;
> ++	ctx->sess.mackeylen = mac_key_size;
> ++	ctx->sess.mackey = (void*)mac_key;
>   +
> -+	ses_new->array_size = DEFAULT_PREALLOC_PAGES;
> -+	dprintk(2, KERN_DEBUG, "preallocating for %d user pages\n",
> -+			ses_new->array_size);
> -+	ses_new->pages = kzalloc(ses_new->array_size *
> -+			sizeof(struct page *), GFP_KERNEL);
> -+	ses_new->sg = kzalloc(ses_new->array_size *
> -+			sizeof(struct scatterlist), GFP_KERNEL);
> -+	if (ses_new->sg == NULL || ses_new->pages == NULL) {
> -+		dprintk(0, KERN_DEBUG, "Memory error\n");
> -+		ret = -ENOMEM;
> -+		goto error_hash;
> ++	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
> ++		perror("ioctl(CIOCGSESSION)");
> ++		return -1;
>   +	}
>   +
> -+	/* put the new session to the list */
> -+	get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
> -+	mutex_init(&ses_new->sem);
> -+
> -+	mutex_lock(&fcr->sem);
> -+restart:
> -+	list_for_each_entry(ses_ptr, &fcr->list, entry) {
> -+		/* Check for duplicate SID */
> -+		if (unlikely(ses_new->sid == ses_ptr->sid)) {
> -+			get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
> -+			/* Unless we have a broken RNG this
> -+			   shouldn't loop forever... ;-) */
> -+			goto restart;
> -+		}
> ++#ifdef CIOCGSESSINFO
> ++	siop.ses = ctx->sess.ses;
> ++	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
> ++		perror("ioctl(CIOCGSESSINFO)");
> ++		return -1;
>   +	}
> -+
> -+	list_add(&ses_new->entry, &fcr->list);
> -+	mutex_unlock(&fcr->sem);
> -+
> -+	/* Fill in some values for the user. */
> -+	sop->ses = ses_new->sid;
> -+
> ++	printf("Got %s with driver %s\n",
> ++			siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
> ++	if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
> ++		printf("Note: This is not an accelerated cipher\n");
> ++	}
> ++	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */
> ++	ctx->alignmask = siop.alignmask;
> ++#endif
>   +	return 0;
> -+
> -+error_hash:
> -+	cryptodev_cipher_deinit(&ses_new->cdata);
> -+	kfree(ses_new->sg);
> -+	kfree(ses_new->pages);
> -+error_cipher:
> -+	kfree(ses_new);
> -+
> -+	return ret;
> -+
>   +}
>   +
> -+/* Everything that needs to be done when remowing a session. */
> -+static inline void
> -+crypto_destroy_session(struct csession *ses_ptr)
> ++void aes_sha1_ctx_deinit(struct cryptodev_ctx* ctx)
>   +{
> -+	if (!mutex_trylock(&ses_ptr->sem)) {
> -+		dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
> -+			ses_ptr->sid);
> -+		mutex_lock(&ses_ptr->sem);
> ++	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
> ++		perror("ioctl(CIOCFSESSION)");
>   +	}
> -+	dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
> -+	cryptodev_cipher_deinit(&ses_ptr->cdata);
> -+	cryptodev_hash_deinit(&ses_ptr->hdata);
> -+	dprintk(2, KERN_DEBUG, "freeing space for %d user pages\n",
> -+			ses_ptr->array_size);
> -+	kfree(ses_ptr->pages);
> -+	kfree(ses_ptr->sg);
> -+	mutex_unlock(&ses_ptr->sem);
> -+	kfree(ses_ptr);
>   +}
>   +
> -+/* Look up a session by ID and remove. */
> -+static int
> -+crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
> ++int
> ++aes_sha1_encrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	void* plaintext, size_t size)
>   +{
> -+	struct csession *tmp, *ses_ptr;
> -+	struct list_head *head;
> -+	int ret = 0;
> -+
> -+	mutex_lock(&fcr->sem);
> -+	head = &fcr->list;
> -+	list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
> -+		if (ses_ptr->sid == sid) {
> -+			list_del(&ses_ptr->entry);
> -+			crypto_destroy_session(ses_ptr);
> -+			break;
> ++	struct crypt_auth_op cryp;
> ++	void* p;
> ++	
> ++	/* check plaintext and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (plaintext != p) {
> ++			fprintf(stderr, "plaintext is not aligned\n");
> ++			return -1;
>   +		}
>   +	}
>   +
> -+	if (unlikely(!ses_ptr)) {
> -+		dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n",
> -+			sid);
> -+		ret = -ENOENT;
> ++	memset(&cryp, 0, sizeof(cryp));
> ++
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.iv = (void*)iv;
> ++	cryp.op = COP_ENCRYPT;
> ++	cryp.auth_len = auth_size;
> ++	cryp.auth_src = (void*)auth;
> ++	cryp.len = size;
> ++	cryp.src = (void*)plaintext;
> ++	cryp.dst = plaintext;
> ++	cryp.flags = COP_FLAG_AEAD_TLS_TYPE;
> ++	if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCAUTHCRYPT)");
> ++		return -1;
>   +	}
> -+	mutex_unlock(&fcr->sem);
>   +
> -+	return ret;
> ++	return 0;
>   +}
>   +
> -+/* Remove all sessions when closing the file */
> -+static int
> -+crypto_finish_all_sessions(struct fcrypt *fcr)
> ++int
> ++aes_sha1_decrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	void* ciphertext, size_t size)
>   +{
> -+	struct csession *tmp, *ses_ptr;
> -+	struct list_head *head;
> ++	struct crypt_auth_op cryp;
> ++	void* p;
> ++	
> ++	/* check plaintext and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (ciphertext != p) {
> ++			fprintf(stderr, "ciphertext is not aligned\n");
> ++			return -1;
> ++		}
> ++	}
>   +
> -+	mutex_lock(&fcr->sem);
> ++	memset(&cryp, 0, sizeof(cryp));
>   +
> -+	head = &fcr->list;
> -+	list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
> -+		list_del(&ses_ptr->entry);
> -+		crypto_destroy_session(ses_ptr);
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.iv = (void*)iv;
> ++	cryp.op = COP_DECRYPT;
> ++	cryp.auth_len = auth_size;
> ++	cryp.auth_src = (void*)auth;
> ++	cryp.len = size;
> ++	cryp.src = (void*)ciphertext;
> ++	cryp.dst = ciphertext;
> ++	cryp.flags = COP_FLAG_AEAD_TLS_TYPE;
> ++	if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCAUTHCRYPT)");
> ++		return -1;
>   +	}
> -+	mutex_unlock(&fcr->sem);
>   +
>   +	return 0;
>   +}
>   +
> -+/* Look up session by session ID. The returned session is locked. */
> -+struct csession *
> -+crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
> -+{
> -+	struct csession *ses_ptr, *retval = NULL;
> +diff --git a/crypto/cryptodev/examples/aes-sha1.h b/crypto/cryptodev/examples/aes-sha1.h
> +new file mode 100644
> +index 0000000..a07334c
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/aes-sha1.h
> +@@ -0,0 +1,31 @@
> ++#ifndef AES_H
> ++# define AES_H
>   +
> -+	if (unlikely(fcr == NULL))
> -+		return NULL;
> ++#include <stdint.h>
>   +
> -+	mutex_lock(&fcr->sem);
> -+	list_for_each_entry(ses_ptr, &fcr->list, entry) {
> -+		if (ses_ptr->sid == sid) {
> -+			mutex_lock(&ses_ptr->sem);
> -+			retval = ses_ptr;
> -+			break;
> -+		}
> -+	}
> -+	mutex_unlock(&fcr->sem);
> ++struct cryptodev_ctx {
> ++	int cfd;
> ++	struct session_op sess;
> ++	uint16_t alignmask;
> ++};
>   +
> -+	return retval;
> -+}
> ++#define	AES_BLOCK_SIZE	16
>   +
> -+static void cryptask_routine(struct work_struct *work)
> -+{
> -+	struct crypt_priv *pcr = container_of(work, struct crypt_priv, cryptask);
> -+	struct todo_list_item *item;
> -+	LIST_HEAD(tmp);
> -+
> -+	/* fetch all pending jobs into the temporary list */
> -+	mutex_lock(&pcr->todo.lock);
> -+	list_cut_position(&tmp, &pcr->todo.list, pcr->todo.list.prev);
> -+	mutex_unlock(&pcr->todo.lock);
> ++int aes_sha1_ctx_init(struct cryptodev_ctx* ctx, int cfd,
> ++	const uint8_t *key, unsigned int key_size,
> ++	const uint8_t *mac_key, unsigned int mac_key_size);
> ++void aes_sha1_ctx_deinit();
>   +
> -+	/* handle each job locklessly */
> -+	list_for_each_entry(item, &tmp, __hook) {
> -+		item->result = crypto_run(&pcr->fcrypt, &item->kcop);
> -+		if (unlikely(item->result))
> -+			dprintk(0, KERN_ERR, "crypto_run() failed: %d\n",
> -+					item->result);
> -+	}
> ++/* Note that encryption assumes that ciphertext has enough size
> ++ * for the tag and padding to be appended.
> ++ *
> ++ * Only in-place encryption and decryption are supported.
> ++ */
> ++int aes_sha1_encrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	void* plaintext, size_t size);
> ++int aes_sha1_decrypt(struct cryptodev_ctx* ctx, const void* iv,
> ++	const void* auth, size_t auth_size,
> ++	void* ciphertext, size_t size);
>   +
> -+	/* push all handled jobs to the done list at once */
> -+	mutex_lock(&pcr->done.lock);
> -+	list_splice_tail(&tmp, &pcr->done.list);
> -+	mutex_unlock(&pcr->done.lock);
> ++#endif
> +diff --git a/crypto/cryptodev/examples/aes.c b/crypto/cryptodev/examples/aes.c
> +new file mode 100644
> +index 0000000..02f7613
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/aes.c
> +@@ -0,0 +1,242 @@
> ++/*
> ++ * Demo on how to use /dev/crypto device for ciphering.
> ++ *
> ++ * Placed under public domain.
> ++ *
> ++ */
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include "aes.h"
>   +
> -+	/* wake for POLLIN */
> -+	wake_up_interruptible(&pcr->user_waiter);
> -+}
> ++#define	KEY_SIZE	16
>   +
> -+/* ====== /dev/crypto ====== */
>   +
> -+static int
> -+cryptodev_open(struct inode *inode, struct file *filp)
> ++int aes_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size)
>   +{
> -+	struct todo_list_item *tmp;
> -+	struct crypt_priv *pcr;
> -+	int i;
> ++#ifdef CIOCGSESSINFO
> ++	struct session_info_op siop;
> ++#endif
>   +
> -+	pcr = kmalloc(sizeof(*pcr), GFP_KERNEL);
> -+	if (!pcr)
> -+		return -ENOMEM;
> ++	memset(ctx, 0, sizeof(*ctx));
> ++	ctx->cfd = cfd;
>   +
> -+	memset(pcr, 0, sizeof(*pcr));
> -+	mutex_init(&pcr->fcrypt.sem);
> -+	INIT_LIST_HEAD(&pcr->fcrypt.list);
> ++	ctx->sess.cipher = CRYPTO_AES_CBC;
> ++	ctx->sess.keylen = key_size;
> ++	ctx->sess.key = (void*)key;
> ++	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
> ++		perror("ioctl(CIOCGSESSION)");
> ++		return -1;
> ++	}
>   +
> -+	INIT_LIST_HEAD(&pcr->free.list);
> -+	INIT_LIST_HEAD(&pcr->todo.list);
> -+	INIT_LIST_HEAD(&pcr->done.list);
> -+	INIT_WORK(&pcr->cryptask, cryptask_routine);
> -+	mutex_init(&pcr->free.lock);
> -+	mutex_init(&pcr->todo.lock);
> -+	mutex_init(&pcr->done.lock);
> -+	init_waitqueue_head(&pcr->user_waiter);
> ++#ifdef CIOCGSESSINFO
> ++	memset(&siop, 0, sizeof(siop));
>   +
> -+	for (i = 0; i < DEF_COP_RINGSIZE; i++) {
> -+		tmp = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL);
> -+		if (!tmp)
> -+			return -ENOMEM;
> -+		pcr->itemcount++;
> -+		dprintk(2, KERN_DEBUG, "allocated new item at %lx\n",
> -+				(unsigned long)tmp);
> -+		list_add(&tmp->__hook, &pcr->free.list);
> ++	siop.ses = ctx->sess.ses;
> ++	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
> ++		perror("ioctl(CIOCGSESSINFO)");
> ++		return -1;
>   +	}
> -+
> -+	filp->private_data = pcr;
> -+	dprintk(2, KERN_DEBUG,
> -+	        "Cryptodev handle initialised, %d elements in queue\n",
> -+		DEF_COP_RINGSIZE);
> ++	printf("Got %s with driver %s\n",
> ++			siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
> ++	if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
> ++		printf("Note: This is not an accelerated cipher\n");
> ++	}
> ++	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */
> ++	ctx->alignmask = siop.alignmask;
> ++#endif
>   +	return 0;
>   +}
>   +
> -+static int
> -+cryptodev_release(struct inode *inode, struct file *filp)
> ++void aes_ctx_deinit(struct cryptodev_ctx* ctx)
>   +{
> -+	struct crypt_priv *pcr = filp->private_data;
> -+	struct todo_list_item *item, *item_safe;
> -+	int items_freed = 0;
> -+
> -+	if (!pcr)
> -+		return 0;
> -+
> -+	cancel_work_sync(&pcr->cryptask);
> -+
> -+	mutex_destroy(&pcr->todo.lock);
> -+	mutex_destroy(&pcr->done.lock);
> -+	mutex_destroy(&pcr->free.lock);
> -+
> -+	list_splice_tail(&pcr->todo.list, &pcr->free.list);
> -+	list_splice_tail(&pcr->done.list, &pcr->free.list);
> ++	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
> ++		perror("ioctl(CIOCFSESSION)");
> ++	}
> ++}
>   +
> -+	list_for_each_entry_safe(item, item_safe, &pcr->free.list, __hook) {
> -+		dprintk(2, KERN_DEBUG, "freeing item at %lx\n",
> -+				(unsigned long)item);
> -+		list_del(&item->__hook);
> -+		kfree(item);
> -+		items_freed++;
> ++int
> ++aes_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size)
> ++{
> ++	struct crypt_op cryp;
> ++	void* p;
> ++	
> ++	/* check plaintext and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (plaintext != p) {
> ++			fprintf(stderr, "plaintext is not aligned\n");
> ++			return -1;
> ++		}
>   +
> -+	}
> -+	if (items_freed != pcr->itemcount) {
> -+		dprintk(0, KERN_ERR,
> -+		        "freed %d items, but %d should exist!\n",
> -+		        items_freed, pcr->itemcount);
> ++		p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (ciphertext != p) {
> ++			fprintf(stderr, "ciphertext is not aligned\n");
> ++			return -1;
> ++		}
>   +	}
>   +
> -+	crypto_finish_all_sessions(&pcr->fcrypt);
> -+	kfree(pcr);
> -+	filp->private_data = NULL;
> -+
> -+	dprintk(2, KERN_DEBUG,
> -+	        "Cryptodev handle deinitialised, %d elements freed\n",
> -+	        items_freed);
> -+	return 0;
> -+}
> ++	memset(&cryp, 0, sizeof(cryp));
>   +
> -+static int
> -+clonefd(struct file *filp)
> -+{
> -+	int ret;
> -+	ret = get_unused_fd();
> -+	if (ret >= 0) {
> -+			get_file(filp);
> -+			fd_install(ret, filp);
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.len = size;
> ++	cryp.src = (void*)plaintext;
> ++	cryp.dst = ciphertext;
> ++	cryp.iv = (void*)iv;
> ++	cryp.op = COP_ENCRYPT;
> ++	if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCCRYPT)");
> ++		return -1;
>   +	}
>   +
> -+	return ret;
> ++	return 0;
>   +}
>   +
> -+#ifdef ENABLE_ASYNC
> -+/* enqueue a job for asynchronous completion
> -+ *
> -+ * returns:
> -+ * -EBUSY when there are no free queue slots left
> -+ *        (and the number of slots has reached it MAX_COP_RINGSIZE)
> -+ * -EFAULT when there was a memory allocation error
> -+ * 0 on success */
> -+static int crypto_async_run(struct crypt_priv *pcr, struct kernel_crypt_op *kcop)
> ++int
> ++aes_decrypt(struct cryptodev_ctx* ctx, const void* iv, const void* ciphertext, void* plaintext, size_t size)
>   +{
> -+	struct todo_list_item *item = NULL;
> ++	struct crypt_op cryp;
> ++	void* p;
>   +	
> -+	if (unlikely(kcop->cop.flags & COP_FLAG_NO_ZC))
> -+		return -EINVAL;
> -+
> -+	mutex_lock(&pcr->free.lock);
> -+	if (likely(!list_empty(&pcr->free.list))) {
> -+		item = list_first_entry(&pcr->free.list,
> -+				struct todo_list_item, __hook);
> -+		list_del(&item->__hook);
> -+	} else if (pcr->itemcount < MAX_COP_RINGSIZE) {
> -+		pcr->itemcount++;
> -+	} else {
> -+		mutex_unlock(&pcr->free.lock);
> -+		return -EBUSY;
> -+	}
> -+	mutex_unlock(&pcr->free.lock);
> ++	/* check plaintext and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (plaintext != p) {
> ++			fprintf(stderr, "plaintext is not aligned\n");
> ++			return -1;
> ++		}
>   +
> -+	if (unlikely(!item)) {
> -+		item = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL);
> -+		if (unlikely(!item))
> -+			return -EFAULT;
> -+		dprintk(1, KERN_INFO, "increased item count to %d\n",
> -+				pcr->itemcount);
> ++		p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
> ++		if (ciphertext != p) {
> ++			fprintf(stderr, "ciphertext is not aligned\n");
> ++			return -1;
> ++		}
>   +	}
>   +
> -+	memcpy(&item->kcop, kcop, sizeof(struct kernel_crypt_op));
> ++	memset(&cryp, 0, sizeof(cryp));
>   +
> -+	mutex_lock(&pcr->todo.lock);
> -+	list_add_tail(&item->__hook, &pcr->todo.list);
> -+	mutex_unlock(&pcr->todo.lock);
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.len = size;
> ++	cryp.src = (void*)ciphertext;
> ++	cryp.dst = plaintext;
> ++	cryp.iv = (void*)iv;
> ++	cryp.op = COP_DECRYPT;
> ++	if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCCRYPT)");
> ++		return -1;
> ++	}
>   +
> -+	queue_work(cryptodev_wq, &pcr->cryptask);
>   +	return 0;
>   +}
>   +
> -+/* get the first completed job from the "done" queue
> -+ *
> -+ * returns:
> -+ * -EBUSY if no completed jobs are ready (yet)
> -+ * the return value of crypto_run() otherwise */
> -+static int crypto_async_fetch(struct crypt_priv *pcr,
> -+		struct kernel_crypt_op *kcop)
> ++static int test_aes(int cfd)
>   +{
> -+	struct todo_list_item *item;
> -+	int retval;
> ++	char plaintext1_raw[AES_BLOCK_SIZE + 63], *plaintext1;
> ++	char ciphertext1[AES_BLOCK_SIZE] = { 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 0xb8, 0x7b, 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 };
> ++	char iv1[AES_BLOCK_SIZE];
> ++	uint8_t key1[KEY_SIZE] = { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
> ++	char plaintext2_data[AES_BLOCK_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 };
> ++	char plaintext2_raw[AES_BLOCK_SIZE + 63], *plaintext2;
> ++	char ciphertext2[AES_BLOCK_SIZE] = { 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 0x4b, 0x90, 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 };
> ++	char iv2[AES_BLOCK_SIZE];
> ++	uint8_t key2[KEY_SIZE];
> ++	struct cryptodev_ctx ctx;
> ++
> ++	aes_ctx_init(&ctx, cfd, key1, sizeof(key1));
> ++
> ++	if (ctx.alignmask)
> ++		plaintext1 = (char *)(((unsigned long)plaintext1_raw + ctx.alignmask) & ~ctx.alignmask);
> ++	else
> ++		plaintext1 = plaintext1_raw;
>   +
> -+	mutex_lock(&pcr->done.lock);
> -+	if (list_empty(&pcr->done.list)) {
> -+		mutex_unlock(&pcr->done.lock);
> -+		return -EBUSY;
> -+	}
> -+	item = list_first_entry(&pcr->done.list, struct todo_list_item, __hook);
> -+	list_del(&item->__hook);
> -+	mutex_unlock(&pcr->done.lock);
> ++	memset(plaintext1, 0x0, AES_BLOCK_SIZE);
> ++	memset(iv1, 0x0, sizeof(iv1));
>   +
> -+	memcpy(kcop, &item->kcop, sizeof(struct kernel_crypt_op));
> -+	retval = item->result;
> ++	aes_encrypt(&ctx, iv1, plaintext1, plaintext1, AES_BLOCK_SIZE);
>   +
> -+	mutex_lock(&pcr->free.lock);
> -+	list_add_tail(&item->__hook, &pcr->free.list);
> -+	mutex_unlock(&pcr->free.lock);
> ++	/* Verify the result */
> ++	if (memcmp(plaintext1, ciphertext1, AES_BLOCK_SIZE) != 0) {
> ++		fprintf(stderr,
> ++			"FAIL: Decrypted data are different from the input data.\n");
> ++		return -1;
> ++	}
> ++	
> ++	aes_ctx_deinit(&ctx);
>   +
> -+	/* wake for POLLOUT */
> -+	wake_up_interruptible(&pcr->user_waiter);
> ++	/* Test 2 */
>   +
> -+	return retval;
> -+}
> -+#endif
> ++	memset(key2, 0x0, sizeof(key2));
> ++	memset(iv2, 0x0, sizeof(iv2));
>   +
> -+/* this function has to be called from process context */
> -+static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
> -+{
> -+	struct crypt_op *cop = &kcop->cop;
> -+	struct csession *ses_ptr;
> -+	int rc;
> ++	aes_ctx_init(&ctx, cfd, key2, sizeof(key2));
>   +
> -+	/* this also enters ses_ptr->sem */
> -+	ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
> -+	if (unlikely(!ses_ptr)) {
> -+		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
> -+		return -EINVAL;
> ++	if (ctx.alignmask) {
> ++		plaintext2 = (char *)(((unsigned long)plaintext2_raw + ctx.alignmask) & ~ctx.alignmask);
> ++	} else {
> ++		plaintext2 = plaintext2_raw;
>   +	}
> -+	kcop->ivlen = cop->iv ? ses_ptr->cdata.ivsize : 0;
> -+	kcop->digestsize = 0; /* will be updated during operation */
> -+
> -+	crypto_put_session(ses_ptr);
> ++	memcpy(plaintext2, plaintext2_data, AES_BLOCK_SIZE);
>   +
> -+	kcop->task = current;
> -+	kcop->mm = current->mm;
> ++	/* Encrypt data.in to data.encrypted */
> ++	aes_encrypt(&ctx, iv2, plaintext2, plaintext2, AES_BLOCK_SIZE);
>   +
> -+	if (cop->iv) {
> -+		rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen);
> -+		if (unlikely(rc)) {
> -+			dprintk(1, KERN_ERR,
> -+				"error copying IV (%d bytes), copy_from_user returned %d for address %lx\n",
> -+				kcop->ivlen, rc, (unsigned long)cop->iv);
> -+			return -EFAULT;
> ++	/* Verify the result */
> ++	if (memcmp(plaintext2, ciphertext2, AES_BLOCK_SIZE) != 0) {
> ++		int i;
> ++		fprintf(stderr,
> ++			"FAIL: Decrypted data are different from the input data.\n");
> ++		printf("plaintext:");
> ++		for (i = 0; i < AES_BLOCK_SIZE; i++) {
> ++			printf("%02x ", plaintext2[i]);
> ++		}
> ++		printf("ciphertext:");
> ++		for (i = 0; i < AES_BLOCK_SIZE; i++) {
> ++			printf("%02x ", ciphertext2[i]);
>   +		}
> ++		printf("\n");
> ++		return 1;
>   +	}
> ++	
> ++	aes_ctx_deinit(&ctx);
> ++
> ++	printf("AES Test passed\n");
>   +
>   +	return 0;
>   +}
>   +
> -+/* this function has to be called from process context */
> -+static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
> ++int
> ++main()
>   +{
> -+	int ret;
> ++	int cfd = -1;
>   +
> -+	if (kcop->digestsize) {
> -+		ret = copy_to_user(kcop->cop.mac,
> -+				kcop->hash_output, kcop->digestsize);
> -+		if (unlikely(ret))
> -+			return -EFAULT;
> ++	/* Open the crypto device */
> ++	cfd = open("/dev/crypto", O_RDWR, 0);
> ++	if (cfd < 0) {
> ++		perror("open(/dev/crypto)");
> ++		return 1;
>   +	}
> -+	if (kcop->ivlen && kcop->cop.flags & COP_FLAG_WRITE_IV) {
> -+		ret = copy_to_user(kcop->cop.iv,
> ++
> ++	/* Set close-on-exec (not really neede here) */
> ++	if (fcntl(cfd, F_SETFD, 1) == -1) {
> ++		perror("fcntl(F_SETFD)");
> ++		return 1;
> ++	}
> ++
> ++	/* Run the test itself */
> ++	if (test_aes(cfd))
> ++		return 1;
> ++
> ++	/* Close the original descriptor */
> ++	if (close(cfd)) {
> ++		perror("close(cfd)");
> ++		return 1;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> +diff --git a/crypto/cryptodev/examples/aes.h b/crypto/cryptodev/examples/aes.h
> +new file mode 100644
> +index 0000000..ade90c9
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/aes.h
> +@@ -0,0 +1,19 @@
> ++#ifndef AES_H
> ++# define AES_H
> ++
> ++#include <stdint.h>
> ++
> ++struct cryptodev_ctx {
> ++	int cfd;
> ++	struct session_op sess;
> ++	uint16_t alignmask;
> ++};
> ++
> ++#define	AES_BLOCK_SIZE	16
> ++
> ++int aes_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size);
> ++void aes_ctx_deinit();
> ++int aes_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size);
> ++int aes_decrypt(struct cryptodev_ctx* ctx, const void* iv, const void* ciphertext, void* plaintext, size_t size);
> ++
> ++#endif
> +diff --git a/crypto/cryptodev/examples/sha.c b/crypto/cryptodev/examples/sha.c
> +new file mode 100644
> +index 0000000..4f45a6b
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/sha.c
> +@@ -0,0 +1,137 @@
> ++/*
> ++ * Demo on how to use /dev/crypto device for ciphering.
> ++ *
> ++ * Placed under public domain.
> ++ *
> ++ */
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include "sha.h"
> ++
> ++int sha_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size)
> ++{
> ++#ifdef CIOCGSESSINFO
> ++	struct session_info_op siop;
> ++#endif
> ++
> ++	memset(ctx, 0, sizeof(*ctx));
> ++	ctx->cfd = cfd;
> ++
> ++	if (key == NULL)
> ++		ctx->sess.mac = CRYPTO_SHA1;
> ++	else {
> ++		ctx->sess.mac = CRYPTO_SHA1_HMAC;
> ++		ctx->sess.mackeylen = key_size;
> ++		ctx->sess.mackey = (void*)key;
> ++	}
> ++	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
> ++		perror("ioctl(CIOCGSESSION)");
> ++		return -1;
> ++	}
> ++
> ++#ifdef CIOCGSESSINFO
> ++	siop.ses = ctx->sess.ses;
> ++	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
> ++		perror("ioctl(CIOCGSESSINFO)");
> ++		return -1;
> ++	}
> ++	printf("Got %s with driver %s\n",
> ++			siop.hash_info.cra_name, siop.hash_info.cra_driver_name);
> ++	if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
> ++		printf("Note: This is not an accelerated cipher\n");
> ++	}
> ++	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/
> ++	ctx->alignmask = siop.alignmask;
> ++#endif
> ++	return 0;
> ++}
> ++
> ++void sha_ctx_deinit(struct cryptodev_ctx* ctx)
> ++{
> ++	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
> ++		perror("ioctl(CIOCFSESSION)");
> ++	}
> ++}
> ++
> ++int
> ++sha_hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest)
> ++{
> ++	struct crypt_op cryp;
> ++	void* p;
> ++	
> ++	/* check text and ciphertext alignment */
> ++	if (ctx->alignmask) {
> ++		p = (void*)(((unsigned long)text + ctx->alignmask) & ~ctx->alignmask);
> ++		if (text != p) {
> ++			fprintf(stderr, "text is not aligned\n");
> ++			return -1;
> ++		}
> ++	}
> ++
> ++	memset(&cryp, 0, sizeof(cryp));
> ++
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.len = size;
> ++	cryp.src = (void*)text;
> ++	cryp.mac = digest;
> ++	if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCCRYPT)");
> ++		return -1;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++int
> ++main()
> ++{
> ++	int cfd = -1, i;
> ++	struct cryptodev_ctx ctx;
> ++	uint8_t digest[20];
> ++	char text[] = "The quick brown fox jumps over the lazy dog";
> ++	uint8_t expected[] = "\x2f\xd4\xe1\xc6\x7a\x2d\x28\xfc\xed\x84\x9e\xe1\xbb\x76\xe7\x39\x1b\x93\xeb\x12";
> ++
> ++	/* Open the crypto device */
> ++	cfd = open("/dev/crypto", O_RDWR, 0);
> ++	if (cfd < 0) {
> ++		perror("open(/dev/crypto)");
> ++		return 1;
> ++	}
> ++
> ++	/* Set close-on-exec (not really neede here) */
> ++	if (fcntl(cfd, F_SETFD, 1) == -1) {
> ++		perror("fcntl(F_SETFD)");
> ++		return 1;
> ++	}
> ++
> ++	sha_ctx_init(&ctx, cfd, NULL, 0);
> ++	
> ++	sha_hash(&ctx, text, strlen(text), digest);
> ++	
> ++	sha_ctx_deinit(&ctx);
> ++
> ++	printf("digest: ");
> ++	for (i = 0; i < 20; i++) {
> ++		printf("%02x:", digest[i]);
> ++	}
> ++	printf("\n");
> ++	
> ++	if (memcmp(digest, expected, 20) != 0) {
> ++		fprintf(stderr, "SHA1 hashing failed\n");
> ++		return 1;
> ++	}
> ++
> ++	/* Close the original descriptor */
> ++	if (close(cfd)) {
> ++		perror("close(cfd)");
> ++		return 1;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> +diff --git a/crypto/cryptodev/examples/sha.h b/crypto/cryptodev/examples/sha.h
> +new file mode 100644
> +index 0000000..ed0b8ce
> +--- /dev/null
> ++++ b/crypto/cryptodev/examples/sha.h
> +@@ -0,0 +1,16 @@
> ++#ifndef SHA_H
> ++# define SHA_H
> ++
> ++#include <stdint.h>
> ++
> ++struct cryptodev_ctx {
> ++	int cfd;
> ++	struct session_op sess;
> ++	uint16_t alignmask;
> ++};
> ++
> ++int sha_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size);
> ++void sha_ctx_deinit();
> ++int sha_hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest);
> ++
> ++#endif
> +diff --git a/crypto/cryptodev/ioctl.c b/crypto/cryptodev/ioctl.c
> +new file mode 100644
> +index 0000000..5a55a76
> +--- /dev/null
> ++++ b/crypto/cryptodev/ioctl.c
> +@@ -0,0 +1,1169 @@
> ++/*
> ++ * Driver for /dev/crypto device (aka CryptoDev)
> ++ *
> ++ * Copyright (c) 2004 Michal Ludvig <mludvig at logix.net.nz>, SuSE Labs
> ++ * Copyright (c) 2009,2010,2011 Nikos Mavrogiannopoulos <nmav at gnutls.org>
> ++ * Copyright (c) 2010 Phil Sutter
> ++ *
> ++ * This file is part of linux cryptodev.
> ++ *
> ++ * This program is free software; you can redistribute it and/or
> ++ * modify it under the terms of the GNU General Public License
> ++ * as published by the Free Software Foundation; either version 2
> ++ * of the License, or (at your option) any later version.
> ++ *
> ++ * 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
> ++ */
> ++
> ++/*
> ++ * Device /dev/crypto provides an interface for
> ++ * accessing kernel CryptoAPI algorithms (ciphers,
> ++ * hashes) from userspace programs.
> ++ *
> ++ * /dev/crypto interface was originally introduced in
> ++ * OpenBSD and this module attempts to keep the API.
> ++ *
> ++ */
> ++
> ++#include <crypto/hash.h>
> ++#include <linux/crypto.h>
> ++#include <linux/mm.h>
> ++#include <linux/highmem.h>
> ++#include <linux/ioctl.h>
> ++#include <linux/random.h>
> ++#include <linux/syscalls.h>
> ++#include <linux/pagemap.h>
> ++#include <linux/poll.h>
> ++#include <linux/uaccess.h>
> ++#include <crypto/cryptodev.h>
> ++#include <linux/scatterlist.h>
> ++#include <linux/rtnetlink.h>
> ++#include <crypto/authenc.h>
> ++
> ++#include <linux/sysctl.h>
> ++
> ++#include "cryptodev_int.h"
> ++#include "zc.h"
> ++#include "version.h"
> ++
> ++MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav at gnutls.org>");
> ++MODULE_DESCRIPTION("CryptoDev driver");
> ++MODULE_LICENSE("GPL");
> ++
> ++/* ====== Compile-time config ====== */
> ++
> ++/* Default (pre-allocated) and maximum size of the job queue.
> ++ * These are free, pending and done items all together. */
> ++#define DEF_COP_RINGSIZE 16
> ++#define MAX_COP_RINGSIZE 64
> ++
> ++/* ====== Module parameters ====== */
> ++
> ++int cryptodev_verbosity;
> ++module_param(cryptodev_verbosity, int, 0644);
> ++MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
> ++
> ++/* ====== CryptoAPI ====== */
> ++struct todo_list_item {
> ++	struct list_head __hook;
> ++	struct kernel_crypt_op kcop;
> ++	int result;
> ++};
> ++
> ++struct locked_list {
> ++	struct list_head list;
> ++	struct mutex lock;
> ++};
> ++
> ++struct crypt_priv {
> ++	struct fcrypt fcrypt;
> ++	struct locked_list free, todo, done;
> ++	int itemcount;
> ++	struct work_struct cryptask;
> ++	wait_queue_head_t user_waiter;
> ++};
> ++
> ++#define FILL_SG(sg, ptr, len)					\
> ++	do {							\
> ++		(sg)->page = virt_to_page(ptr);			\
> ++		(sg)->offset = offset_in_page(ptr);		\
> ++		(sg)->length = len;				\
> ++		(sg)->dma_address = 0;				\
> ++	} while (0)
> ++
> ++/* cryptodev's own workqueue, keeps crypto tasks from disturbing the force */
> ++static struct workqueue_struct *cryptodev_wq;
> ++
> ++/* Prepare session for future use. */
> ++static int
> ++crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
> ++{
> ++	struct csession	*ses_new = NULL, *ses_ptr;
> ++	int ret = 0;
> ++	const char *alg_name = NULL;
> ++	const char *hash_name = NULL;
> ++	int hmac_mode = 1, stream = 0, aead = 0;
> ++	/*
> ++	 * With composite aead ciphers, only ckey is used and it can cover all the
> ++	 * structure space; otherwise both keys may be used simultaneously but they
> ++	 * are confined to their spaces
> ++	 */
> ++	struct {
> ++		uint8_t ckey[CRYPTO_CIPHER_MAX_KEY_LEN];
> ++		uint8_t mkey[CRYPTO_HMAC_MAX_KEY_LEN];
> ++		/* padding space for aead keys */
> ++		uint8_t pad[RTA_SPACE(sizeof(struct crypto_authenc_key_param))];
> ++	} keys;
> ++
> ++	/* Does the request make sense? */
> ++	if (unlikely(!sop->cipher && !sop->mac)) {
> ++		ddebug(1, "Both 'cipher' and 'mac' unset.");
> ++		return -EINVAL;
> ++	}
> ++
> ++	switch (sop->cipher) {
> ++	case 0:
> ++		break;
> ++	case CRYPTO_DES_CBC:
> ++		alg_name = "cbc(des)";
> ++		break;
> ++	case CRYPTO_3DES_CBC:
> ++		alg_name = "cbc(des3_ede)";
> ++		break;
> ++	case CRYPTO_BLF_CBC:
> ++		alg_name = "cbc(blowfish)";
> ++		break;
> ++	case CRYPTO_AES_CBC:
> ++		alg_name = "cbc(aes)";
> ++		break;
> ++	case CRYPTO_AES_ECB:
> ++		alg_name = "ecb(aes)";
> ++		break;
> ++	case CRYPTO_CAMELLIA_CBC:
> ++		alg_name = "cbc(camellia)";
> ++		break;
> ++	case CRYPTO_AES_CTR:
> ++		alg_name = "ctr(aes)";
> ++		stream = 1;
> ++		break;
> ++	case CRYPTO_AES_GCM:
> ++		alg_name = "gcm(aes)";
> ++		stream = 1;
> ++		aead = 1;
> ++		break;
> ++	case CRYPTO_NULL:
> ++		alg_name = "ecb(cipher_null)";
> ++		stream = 1;
> ++		break;
> ++	default:
> ++		ddebug(1, "bad cipher: %d", sop->cipher);
> ++		return -EINVAL;
> ++	}
> ++
> ++	switch (sop->mac) {
> ++	case 0:
> ++		break;
> ++	case CRYPTO_MD5_HMAC:
> ++		hash_name = "hmac(md5)";
> ++		break;
> ++	case CRYPTO_RIPEMD160_HMAC:
> ++		hash_name = "hmac(rmd160)";
> ++		break;
> ++	case CRYPTO_SHA1_HMAC:
> ++		hash_name = "hmac(sha1)";
> ++		break;
> ++	case CRYPTO_SHA2_224_HMAC:
> ++		hash_name = "hmac(sha224)";
> ++		break;
> ++
> ++	case CRYPTO_SHA2_256_HMAC:
> ++		hash_name = "hmac(sha256)";
> ++		break;
> ++	case CRYPTO_SHA2_384_HMAC:
> ++		hash_name = "hmac(sha384)";
> ++		break;
> ++	case CRYPTO_SHA2_512_HMAC:
> ++		hash_name = "hmac(sha512)";
> ++		break;
> ++
> ++	/* non-hmac cases */
> ++	case CRYPTO_MD5:
> ++		hash_name = "md5";
> ++		hmac_mode = 0;
> ++		break;
> ++	case CRYPTO_RIPEMD160:
> ++		hash_name = "rmd160";
> ++		hmac_mode = 0;
> ++		break;
> ++	case CRYPTO_SHA1:
> ++		hash_name = "sha1";
> ++		hmac_mode = 0;
> ++		break;
> ++	case CRYPTO_SHA2_224:
> ++		hash_name = "sha224";
> ++		hmac_mode = 0;
> ++		break;
> ++	case CRYPTO_SHA2_256:
> ++		hash_name = "sha256";
> ++		hmac_mode = 0;
> ++		break;
> ++	case CRYPTO_SHA2_384:
> ++		hash_name = "sha384";
> ++		hmac_mode = 0;
> ++		break;
> ++	case CRYPTO_SHA2_512:
> ++		hash_name = "sha512";
> ++		hmac_mode = 0;
> ++		break;
> ++	default:
> ++		ddebug(1, "bad mac: %d", sop->mac);
> ++		return -EINVAL;
> ++	}
> ++
> ++	/* Create a session and put it to the list. */
> ++	ses_new = kzalloc(sizeof(*ses_new), GFP_KERNEL);
> ++	if (!ses_new)
> ++		return -ENOMEM;
> ++
> ++	/* Set-up crypto transform. */
> ++	if (alg_name) {
> ++		unsigned int keylen;
> ++		ret = cryptodev_get_cipher_keylen(&keylen, sop, aead);
> ++		if (unlikely(ret < 0)) {
> ++			ddebug(1, "Setting key failed for %s-%zu.",
> ++				alg_name, (size_t)sop->keylen*8);
> ++			goto error_cipher;
> ++		}
> ++
> ++		ret = cryptodev_get_cipher_key(keys.ckey, sop, aead);
> ++		if (unlikely(ret < 0))
> ++			goto error_cipher;
> ++
> ++		ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keys.ckey,
> ++						keylen, stream, aead);
> ++		if (ret < 0) {
> ++			ddebug(1, "Failed to load cipher for %s", alg_name);
> ++			ret = -EINVAL;
> ++			goto error_cipher;
> ++		}
> ++	}
> ++
> ++	if (hash_name && aead == 0) {
> ++		if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
> ++			ddebug(1, "Setting key failed for %s-%zu.",
> ++				hash_name, (size_t)sop->mackeylen*8);
> ++			ret = -EINVAL;
> ++			goto error_hash;
> ++		}
> ++
> ++		if (sop->mackey && unlikely(copy_from_user(keys.mkey, sop->mackey,
> ++					    sop->mackeylen))) {
> ++			ret = -EFAULT;
> ++			goto error_hash;
> ++		}
> ++
> ++		ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode,
> ++							keys.mkey, sop->mackeylen);
> ++		if (ret != 0) {
> ++			ddebug(1, "Failed to load hash for %s", hash_name);
> ++			ret = -EINVAL;
> ++			goto error_hash;
> ++		}
> ++	}
> ++
> ++	ses_new->alignmask = max(ses_new->cdata.alignmask,
> ++	                                          ses_new->hdata.alignmask);
> ++	ddebug(2, "got alignmask %d", ses_new->alignmask);
> ++
> ++	ses_new->array_size = DEFAULT_PREALLOC_PAGES;
> ++	ddebug(2, "preallocating for %d user pages", ses_new->array_size);
> ++	ses_new->pages = kzalloc(ses_new->array_size *
> ++			sizeof(struct page *), GFP_KERNEL);
> ++	ses_new->sg = kzalloc(ses_new->array_size *
> ++			sizeof(struct scatterlist), GFP_KERNEL);
> ++	if (ses_new->sg == NULL || ses_new->pages == NULL) {
> ++		ddebug(0, "Memory error");
> ++		ret = -ENOMEM;
> ++		goto error_hash;
> ++	}
> ++
> ++	/* put the new session to the list */
> ++	get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
> ++	mutex_init(&ses_new->sem);
> ++
> ++	mutex_lock(&fcr->sem);
> ++restart:
> ++	list_for_each_entry(ses_ptr, &fcr->list, entry) {
> ++		/* Check for duplicate SID */
> ++		if (unlikely(ses_new->sid == ses_ptr->sid)) {
> ++			get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
> ++			/* Unless we have a broken RNG this
> ++			   shouldn't loop forever... ;-) */
> ++			goto restart;
> ++		}
> ++	}
> ++
> ++	list_add(&ses_new->entry, &fcr->list);
> ++	mutex_unlock(&fcr->sem);
> ++
> ++	/* Fill in some values for the user. */
> ++	sop->ses = ses_new->sid;
> ++
> ++	return 0;
> ++
> ++error_hash:
> ++	cryptodev_cipher_deinit(&ses_new->cdata);
> ++	kfree(ses_new->sg);
> ++	kfree(ses_new->pages);
> ++error_cipher:
> ++	kfree(ses_new);
> ++
> ++	return ret;
> ++
> ++}
> ++
> ++/* Everything that needs to be done when remowing a session. */
> ++static inline void
> ++crypto_destroy_session(struct csession *ses_ptr)
> ++{
> ++	if (!mutex_trylock(&ses_ptr->sem)) {
> ++		ddebug(2, "Waiting for semaphore of sid=0x%08X", ses_ptr->sid);
> ++		mutex_lock(&ses_ptr->sem);
> ++	}
> ++	ddebug(2, "Removed session 0x%08X", ses_ptr->sid);
> ++	cryptodev_cipher_deinit(&ses_ptr->cdata);
> ++	cryptodev_hash_deinit(&ses_ptr->hdata);
> ++	ddebug(2, "freeing space for %d user pages", ses_ptr->array_size);
> ++	kfree(ses_ptr->pages);
> ++	kfree(ses_ptr->sg);
> ++	mutex_unlock(&ses_ptr->sem);
> ++	mutex_destroy(&ses_ptr->sem);
> ++	kfree(ses_ptr);
> ++}
> ++
> ++/* Look up a session by ID and remove. */
> ++static int
> ++crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
> ++{
> ++	struct csession *tmp, *ses_ptr;
> ++	struct list_head *head;
> ++	int ret = 0;
> ++
> ++	mutex_lock(&fcr->sem);
> ++	head = &fcr->list;
> ++	list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
> ++		if (ses_ptr->sid == sid) {
> ++			list_del(&ses_ptr->entry);
> ++			crypto_destroy_session(ses_ptr);
> ++			break;
> ++		}
> ++	}
> ++
> ++	if (unlikely(!ses_ptr)) {
> ++		derr(1, "Session with sid=0x%08X not found!", sid);
> ++		ret = -ENOENT;
> ++	}
> ++	mutex_unlock(&fcr->sem);
> ++
> ++	return ret;
> ++}
> ++
> ++/* Remove all sessions when closing the file */
> ++static int
> ++crypto_finish_all_sessions(struct fcrypt *fcr)
> ++{
> ++	struct csession *tmp, *ses_ptr;
> ++	struct list_head *head;
> ++
> ++	mutex_lock(&fcr->sem);
> ++
> ++	head = &fcr->list;
> ++	list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
> ++		list_del(&ses_ptr->entry);
> ++		crypto_destroy_session(ses_ptr);
> ++	}
> ++	mutex_unlock(&fcr->sem);
> ++
> ++	return 0;
> ++}
> ++
> ++/* Look up session by session ID. The returned session is locked. */
> ++struct csession *
> ++crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
> ++{
> ++	struct csession *ses_ptr, *retval = NULL;
> ++
> ++	if (unlikely(fcr == NULL))
> ++		return NULL;
> ++
> ++	mutex_lock(&fcr->sem);
> ++	list_for_each_entry(ses_ptr, &fcr->list, entry) {
> ++		if (ses_ptr->sid == sid) {
> ++			mutex_lock(&ses_ptr->sem);
> ++			retval = ses_ptr;
> ++			break;
> ++		}
> ++	}
> ++	mutex_unlock(&fcr->sem);
> ++
> ++	return retval;
> ++}
> ++
> ++static void cryptask_routine(struct work_struct *work)
> ++{
> ++	struct crypt_priv *pcr = container_of(work, struct crypt_priv, cryptask);
> ++	struct todo_list_item *item;
> ++	LIST_HEAD(tmp);
> ++
> ++	/* fetch all pending jobs into the temporary list */
> ++	mutex_lock(&pcr->todo.lock);
> ++	list_cut_position(&tmp, &pcr->todo.list, pcr->todo.list.prev);
> ++	mutex_unlock(&pcr->todo.lock);
> ++
> ++	/* handle each job locklessly */
> ++	list_for_each_entry(item, &tmp, __hook) {
> ++		item->result = crypto_run(&pcr->fcrypt, &item->kcop);
> ++		if (unlikely(item->result))
> ++			derr(0, "crypto_run() failed: %d", item->result);
> ++	}
> ++
> ++	/* push all handled jobs to the done list at once */
> ++	mutex_lock(&pcr->done.lock);
> ++	list_splice_tail(&tmp, &pcr->done.list);
> ++	mutex_unlock(&pcr->done.lock);
> ++
> ++	/* wake for POLLIN */
> ++	wake_up_interruptible(&pcr->user_waiter);
> ++}
> ++
> ++/* ====== /dev/crypto ====== */
> ++
> ++static int
> ++cryptodev_open(struct inode *inode, struct file *filp)
> ++{
> ++	struct todo_list_item *tmp, *tmp_next;
> ++	struct crypt_priv *pcr;
> ++	int i;
> ++
> ++	pcr = kzalloc(sizeof(*pcr), GFP_KERNEL);
> ++	if (!pcr)
> ++		return -ENOMEM;
> ++	filp->private_data = pcr;
> ++
> ++	mutex_init(&pcr->fcrypt.sem);
> ++	mutex_init(&pcr->free.lock);
> ++	mutex_init(&pcr->todo.lock);
> ++	mutex_init(&pcr->done.lock);
> ++
> ++	INIT_LIST_HEAD(&pcr->fcrypt.list);
> ++	INIT_LIST_HEAD(&pcr->free.list);
> ++	INIT_LIST_HEAD(&pcr->todo.list);
> ++	INIT_LIST_HEAD(&pcr->done.list);
> ++
> ++	INIT_WORK(&pcr->cryptask, cryptask_routine);
> ++
> ++	init_waitqueue_head(&pcr->user_waiter);
> ++
> ++	for (i = 0; i < DEF_COP_RINGSIZE; i++) {
> ++		tmp = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL);
> ++		if (!tmp)
> ++			goto err_ringalloc;
> ++		pcr->itemcount++;
> ++		ddebug(2, "allocated new item at %p", tmp);
> ++		list_add(&tmp->__hook, &pcr->free.list);
> ++	}
> ++
> ++	ddebug(2, "Cryptodev handle initialised, %d elements in queue",
> ++			DEF_COP_RINGSIZE);
> ++	return 0;
> ++
> ++/* In case of errors, free any memory allocated so far */
> ++err_ringalloc:
> ++	list_for_each_entry_safe(tmp, tmp_next, &pcr->free.list, __hook) {
> ++		list_del(&tmp->__hook);
> ++		kfree(tmp);
> ++	}
> ++	mutex_destroy(&pcr->done.lock);
> ++	mutex_destroy(&pcr->todo.lock);
> ++	mutex_destroy(&pcr->free.lock);
> ++	mutex_destroy(&pcr->fcrypt.sem);
> ++	kfree(pcr);
> ++	filp->private_data = NULL;
> ++	return -ENOMEM;
> ++}
> ++
> ++static int
> ++cryptodev_release(struct inode *inode, struct file *filp)
> ++{
> ++	struct crypt_priv *pcr = filp->private_data;
> ++	struct todo_list_item *item, *item_safe;
> ++	int items_freed = 0;
> ++
> ++	if (!pcr)
> ++		return 0;
> ++
> ++	cancel_work_sync(&pcr->cryptask);
> ++
> ++	list_splice_tail(&pcr->todo.list, &pcr->free.list);
> ++	list_splice_tail(&pcr->done.list, &pcr->free.list);
> ++
> ++	list_for_each_entry_safe(item, item_safe, &pcr->free.list, __hook) {
> ++		ddebug(2, "freeing item at %p", item);
> ++		list_del(&item->__hook);
> ++		kfree(item);
> ++		items_freed++;
> ++	}
> ++
> ++	if (items_freed != pcr->itemcount) {
> ++		derr(0, "freed %d items, but %d should exist!",
> ++				items_freed, pcr->itemcount);
> ++	}
> ++
> ++	crypto_finish_all_sessions(&pcr->fcrypt);
> ++
> ++	mutex_destroy(&pcr->done.lock);
> ++	mutex_destroy(&pcr->todo.lock);
> ++	mutex_destroy(&pcr->free.lock);
> ++	mutex_destroy(&pcr->fcrypt.sem);
> ++
> ++	kfree(pcr);
> ++	filp->private_data = NULL;
> ++
> ++	ddebug(2, "Cryptodev handle deinitialised, %d elements freed",
> ++			items_freed);
> ++	return 0;
> ++}
> ++
> ++static int
> ++clonefd(struct file *filp)
> ++{
> ++	int ret;
> ++	ret = get_unused_fd();
> ++	if (ret >= 0) {
> ++			get_file(filp);
> ++			fd_install(ret, filp);
> ++	}
> ++
> ++	return ret;
> ++}
> ++
> ++#ifdef ENABLE_ASYNC
> ++/* enqueue a job for asynchronous completion
> ++ *
> ++ * returns:
> ++ * -EBUSY when there are no free queue slots left
> ++ *        (and the number of slots has reached it MAX_COP_RINGSIZE)
> ++ * -EFAULT when there was a memory allocation error
> ++ * 0 on success */
> ++static int crypto_async_run(struct crypt_priv *pcr, struct kernel_crypt_op *kcop)
> ++{
> ++	struct todo_list_item *item = NULL;
> ++
> ++	if (unlikely(kcop->cop.flags & COP_FLAG_NO_ZC))
> ++		return -EINVAL;
> ++
> ++	mutex_lock(&pcr->free.lock);
> ++	if (likely(!list_empty(&pcr->free.list))) {
> ++		item = list_first_entry(&pcr->free.list,
> ++				struct todo_list_item, __hook);
> ++		list_del(&item->__hook);
> ++	} else if (pcr->itemcount < MAX_COP_RINGSIZE) {
> ++		pcr->itemcount++;
> ++	} else {
> ++		mutex_unlock(&pcr->free.lock);
> ++		return -EBUSY;
> ++	}
> ++	mutex_unlock(&pcr->free.lock);
> ++
> ++	if (unlikely(!item)) {
> ++		item = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL);
> ++		if (unlikely(!item))
> ++			return -EFAULT;
> ++		dinfo(1, "increased item count to %d", pcr->itemcount);
> ++	}
> ++
> ++	memcpy(&item->kcop, kcop, sizeof(struct kernel_crypt_op));
> ++
> ++	mutex_lock(&pcr->todo.lock);
> ++	list_add_tail(&item->__hook, &pcr->todo.list);
> ++	mutex_unlock(&pcr->todo.lock);
> ++
> ++	queue_work(cryptodev_wq, &pcr->cryptask);
> ++	return 0;
> ++}
> ++
> ++/* get the first completed job from the "done" queue
> ++ *
> ++ * returns:
> ++ * -EBUSY if no completed jobs are ready (yet)
> ++ * the return value of crypto_run() otherwise */
> ++static int crypto_async_fetch(struct crypt_priv *pcr,
> ++		struct kernel_crypt_op *kcop)
> ++{
> ++	struct todo_list_item *item;
> ++	int retval;
> ++
> ++	mutex_lock(&pcr->done.lock);
> ++	if (list_empty(&pcr->done.list)) {
> ++		mutex_unlock(&pcr->done.lock);
> ++		return -EBUSY;
> ++	}
> ++	item = list_first_entry(&pcr->done.list, struct todo_list_item, __hook);
> ++	list_del(&item->__hook);
> ++	mutex_unlock(&pcr->done.lock);
> ++
> ++	memcpy(kcop, &item->kcop, sizeof(struct kernel_crypt_op));
> ++	retval = item->result;
> ++
> ++	mutex_lock(&pcr->free.lock);
> ++	list_add_tail(&item->__hook, &pcr->free.list);
> ++	mutex_unlock(&pcr->free.lock);
> ++
> ++	/* wake for POLLOUT */
> ++	wake_up_interruptible(&pcr->user_waiter);
> ++
> ++	return retval;
> ++}
> ++#endif
> ++
> ++/* this function has to be called from process context */
> ++static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
> ++{
> ++	struct crypt_op *cop = &kcop->cop;
> ++	struct csession *ses_ptr;
> ++	int rc;
> ++
> ++	/* this also enters ses_ptr->sem */
> ++	ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
> ++	if (unlikely(!ses_ptr)) {
> ++		derr(1, "invalid session ID=0x%08X", cop->ses);
> ++		return -EINVAL;
> ++	}
> ++	kcop->ivlen = cop->iv ? ses_ptr->cdata.ivsize : 0;
> ++	kcop->digestsize = 0; /* will be updated during operation */
> ++
> ++	crypto_put_session(ses_ptr);
> ++
> ++	kcop->task = current;
> ++	kcop->mm = current->mm;
> ++
> ++	if (cop->iv) {
> ++		rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen);
> ++		if (unlikely(rc)) {
> ++			derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p",
> ++					kcop->ivlen, rc, cop->iv);
> ++			return -EFAULT;
> ++		}
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++/* this function has to be called from process context */
> ++static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
> ++{
> ++	int ret;
> ++
> ++	if (kcop->digestsize) {
> ++		ret = copy_to_user(kcop->cop.mac,
> ++				kcop->hash_output, kcop->digestsize);
> ++		if (unlikely(ret))
> ++			return -EFAULT;
> ++	}
> ++	if (kcop->ivlen && kcop->cop.flags & COP_FLAG_WRITE_IV) {
> ++		ret = copy_to_user(kcop->cop.iv,
>   +				kcop->iv, kcop->ivlen);
>   +		if (unlikely(ret))
>   +			return -EFAULT;
> @@ -3045,479 +4065,1123 @@ index 0000000..f26cf93
>   +	return 0;
>   +}
>   +
> -+static int kcop_from_user(struct kernel_crypt_op *kcop,
> -+			struct fcrypt *fcr, void __user *arg)
> -+{
> -+	if (unlikely(copy_from_user(&kcop->cop, arg, sizeof(kcop->cop))))
> -+		return -EFAULT;
> ++static int kcop_from_user(struct kernel_crypt_op *kcop,
> ++			struct fcrypt *fcr, void __user *arg)
> ++{
> ++	if (unlikely(copy_from_user(&kcop->cop, arg, sizeof(kcop->cop))))
> ++		return -EFAULT;
> ++
> ++	return fill_kcop_from_cop(kcop, fcr);
> ++}
> ++
> ++static int kcop_to_user(struct kernel_crypt_op *kcop,
> ++			struct fcrypt *fcr, void __user *arg)
> ++{
> ++	int ret;
> ++
> ++	ret = fill_cop_from_kcop(kcop, fcr);
> ++	if (unlikely(ret)) {
> ++		derr(1, "Error in fill_cop_from_kcop");
> ++		return ret;
> ++	}
> ++
> ++	if (unlikely(copy_to_user(arg, &kcop->cop, sizeof(kcop->cop)))) {
> ++		derr(1, "Cannot copy to userspace");
> ++		return -EFAULT;
> ++	}
> ++	return 0;
> ++}
> ++
> ++static inline void tfm_info_to_alg_info(struct alg_info *dst, struct crypto_tfm *tfm)
> ++{
> ++	snprintf(dst->cra_name, CRYPTODEV_MAX_ALG_NAME,
> ++			"%s", crypto_tfm_alg_name(tfm));
> ++	snprintf(dst->cra_driver_name, CRYPTODEV_MAX_ALG_NAME,
> ++			"%s", crypto_tfm_alg_driver_name(tfm));
> ++}
> ++
> ++#ifndef CRYPTO_ALG_KERN_DRIVER_ONLY
> ++static unsigned int is_known_accelerated(struct crypto_tfm *tfm)
> ++{
> ++	const char *name = crypto_tfm_alg_driver_name(tfm);
> ++
> ++	if (name == NULL)
> ++		return 1; /* assume accelerated */
> ++
> ++	/* look for known crypto engine names */
> ++	if (strstr(name, "-talitos")	||
> ++	    !strncmp(name, "mv-", 3)	||
> ++	    !strncmp(name, "atmel-", 6)	||
> ++	    strstr(name, "geode")	||
> ++	    strstr(name, "hifn")	||
> ++	    strstr(name, "-ixp4xx")	||
> ++	    strstr(name, "-omap")	||
> ++	    strstr(name, "-picoxcell")	||
> ++	    strstr(name, "-s5p")	||
> ++	    strstr(name, "-ppc4xx")	||
> ++	    strstr(name, "-caam")	||
> ++	    strstr(name, "-n2"))
> ++		return 1;
> ++
> ++	return 0;
> ++}
> ++#endif
> ++
> ++static int get_session_info(struct fcrypt *fcr, struct session_info_op *siop)
> ++{
> ++	struct csession *ses_ptr;
> ++	struct crypto_tfm *tfm;
> ++
> ++	/* this also enters ses_ptr->sem */
> ++	ses_ptr = crypto_get_session_by_sid(fcr, siop->ses);
> ++	if (unlikely(!ses_ptr)) {
> ++		derr(1, "invalid session ID=0x%08X", siop->ses);
> ++		return -EINVAL;
> ++	}
> ++
> ++	siop->flags = 0;
> ++
> ++	if (ses_ptr->cdata.init) {
> ++		if (ses_ptr->cdata.aead == 0)
> ++			tfm = crypto_ablkcipher_tfm(ses_ptr->cdata.async.s);
> ++		else
> ++			tfm = crypto_aead_tfm(ses_ptr->cdata.async.as);
> ++		tfm_info_to_alg_info(&siop->cipher_info, tfm);
> ++#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY
> ++		if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY)
> ++			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> ++#else
> ++		if (is_known_accelerated(tfm))
> ++			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> ++#endif
> ++	}
> ++	if (ses_ptr->hdata.init) {
> ++		tfm = crypto_ahash_tfm(ses_ptr->hdata.async.s);
> ++		tfm_info_to_alg_info(&siop->hash_info, tfm);
> ++#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY
> ++		if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY)
> ++			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> ++#else
> ++		if (is_known_accelerated(tfm))
> ++			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> ++#endif
> ++	}
> ++
> ++	siop->alignmask = ses_ptr->alignmask;
> ++
> ++	crypto_put_session(ses_ptr);
> ++	return 0;
> ++}
> ++
> ++static long
> ++cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
> ++{
> ++	void __user *arg = (void __user *)arg_;
> ++	int __user *p = arg;
> ++	struct session_op sop;
> ++	struct kernel_crypt_op kcop;
> ++	struct kernel_crypt_auth_op kcaop;
> ++	struct crypt_priv *pcr = filp->private_data;
> ++	struct fcrypt *fcr;
> ++	struct session_info_op siop;
> ++	uint32_t ses;
> ++	int ret, fd;
> ++
> ++	if (unlikely(!pcr))
> ++		BUG();
> ++
> ++	fcr = &pcr->fcrypt;
> ++
> ++	switch (cmd) {
> ++	case CIOCASYMFEAT:
> ++		return put_user(0, p);
> ++	case CRIOGET:
> ++		fd = clonefd(filp);
> ++		ret = put_user(fd, p);
> ++		if (unlikely(ret)) {
> ++			sys_close(fd);
> ++			return ret;
> ++		}
> ++		return ret;
> ++	case CIOCGSESSION:
> ++		if (unlikely(copy_from_user(&sop, arg, sizeof(sop))))
> ++			return -EFAULT;
> ++
> ++		ret = crypto_create_session(fcr, &sop);
> ++		if (unlikely(ret))
> ++			return ret;
> ++		ret = copy_to_user(arg, &sop, sizeof(sop));
> ++		if (unlikely(ret)) {
> ++			crypto_finish_session(fcr, sop.ses);
> ++			return -EFAULT;
> ++		}
> ++		return ret;
> ++	case CIOCFSESSION:
> ++		ret = get_user(ses, (uint32_t __user *)arg);
> ++		if (unlikely(ret))
> ++			return ret;
> ++		ret = crypto_finish_session(fcr, ses);
> ++		return ret;
> ++	case CIOCGSESSINFO:
> ++		if (unlikely(copy_from_user(&siop, arg, sizeof(siop))))
> ++			return -EFAULT;
> ++
> ++		ret = get_session_info(fcr, &siop);
> ++		if (unlikely(ret))
> ++			return ret;
> ++		return copy_to_user(arg, &siop, sizeof(siop));
> ++	case CIOCCRYPT:
> ++		if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) {
> ++			dwarning(1, "Error copying from user");
> ++			return ret;
> ++		}
> ++
> ++		ret = crypto_run(fcr, &kcop);
> ++		if (unlikely(ret)) {
> ++			dwarning(1, "Error in crypto_run");
> ++			return ret;
> ++		}
> ++
> ++		return kcop_to_user(&kcop, fcr, arg);
> ++	case CIOCAUTHCRYPT:
> ++		if (unlikely(ret = kcaop_from_user(&kcaop, fcr, arg))) {
> ++			dwarning(1, "Error copying from user");
> ++			return ret;
> ++		}
> ++
> ++		ret = crypto_auth_run(fcr, &kcaop);
> ++		if (unlikely(ret)) {
> ++			dwarning(1, "Error in crypto_auth_run");
> ++			return ret;
> ++		}
> ++		return kcaop_to_user(&kcaop, fcr, arg);
> ++#ifdef ENABLE_ASYNC
> ++	case CIOCASYNCCRYPT:
> ++		if (unlikely(ret = kcop_from_user(&kcop, fcr, arg)))
> ++			return ret;
> ++
> ++		return crypto_async_run(pcr, &kcop);
> ++	case CIOCASYNCFETCH:
> ++		ret = crypto_async_fetch(pcr, &kcop);
> ++		if (unlikely(ret))
> ++			return ret;
> ++
> ++		return kcop_to_user(&kcop, fcr, arg);
> ++#endif
> ++	default:
> ++		return -EINVAL;
> ++	}
> ++}
> ++
> ++/* compatibility code for 32bit userlands */
> ++#ifdef CONFIG_COMPAT
> ++
> ++static inline void
> ++compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
> ++{
> ++	sop->cipher = compat->cipher;
> ++	sop->mac = compat->mac;
> ++	sop->keylen = compat->keylen;
> ++
> ++	sop->key       = compat_ptr(compat->key);
> ++	sop->mackeylen = compat->mackeylen;
> ++	sop->mackey    = compat_ptr(compat->mackey);
> ++	sop->ses       = compat->ses;
> ++}
> ++
> ++static inline void
> ++session_op_to_compat(struct session_op *sop, struct compat_session_op *compat)
> ++{
> ++	compat->cipher = sop->cipher;
> ++	compat->mac = sop->mac;
> ++	compat->keylen = sop->keylen;
> ++
> ++	compat->key       = ptr_to_compat(sop->key);
> ++	compat->mackeylen = sop->mackeylen;
> ++	compat->mackey    = ptr_to_compat(sop->mackey);
> ++	compat->ses       = sop->ses;
> ++}
> ++
> ++static inline void
> ++compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop)
> ++{
> ++	cop->ses = compat->ses;
> ++	cop->op = compat->op;
> ++	cop->flags = compat->flags;
> ++	cop->len = compat->len;
> ++
> ++	cop->src = compat_ptr(compat->src);
> ++	cop->dst = compat_ptr(compat->dst);
> ++	cop->mac = compat_ptr(compat->mac);
> ++	cop->iv  = compat_ptr(compat->iv);
> ++}
> ++
> ++static inline void
> ++crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat)
> ++{
> ++	compat->ses = cop->ses;
> ++	compat->op = cop->op;
> ++	compat->flags = cop->flags;
> ++	compat->len = cop->len;
> ++
> ++	compat->src = ptr_to_compat(cop->src);
> ++	compat->dst = ptr_to_compat(cop->dst);
> ++	compat->mac = ptr_to_compat(cop->mac);
> ++	compat->iv  = ptr_to_compat(cop->iv);
> ++}
> ++
> ++static int compat_kcop_from_user(struct kernel_crypt_op *kcop,
> ++                                 struct fcrypt *fcr, void __user *arg)
> ++{
> ++	struct compat_crypt_op compat_cop;
> ++
> ++	if (unlikely(copy_from_user(&compat_cop, arg, sizeof(compat_cop))))
> ++		return -EFAULT;
> ++	compat_to_crypt_op(&compat_cop, &kcop->cop);
> ++
> ++	return fill_kcop_from_cop(kcop, fcr);
> ++}
> ++
> ++static int compat_kcop_to_user(struct kernel_crypt_op *kcop,
> ++                               struct fcrypt *fcr, void __user *arg)
> ++{
> ++	int ret;
> ++	struct compat_crypt_op compat_cop;
> ++
> ++	ret = fill_cop_from_kcop(kcop, fcr);
> ++	if (unlikely(ret)) {
> ++		dwarning(1, "Error in fill_cop_from_kcop");
> ++		return ret;
> ++	}
> ++	crypt_op_to_compat(&kcop->cop, &compat_cop);
> ++
> ++	if (unlikely(copy_to_user(arg, &compat_cop, sizeof(compat_cop)))) {
> ++		dwarning(1, "Error copying to user");
> ++		return -EFAULT;
> ++	}
> ++	return 0;
> ++}
> ++
> ++static long
> ++cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
> ++{
> ++	void __user *arg = (void __user *)arg_;
> ++	struct crypt_priv *pcr = file->private_data;
> ++	struct fcrypt *fcr;
> ++	struct session_op sop;
> ++	struct compat_session_op compat_sop;
> ++	struct kernel_crypt_op kcop;
> ++	int ret;
> ++
> ++	if (unlikely(!pcr))
> ++		BUG();
> ++
> ++	fcr = &pcr->fcrypt;
> ++
> ++	switch (cmd) {
> ++	case CIOCASYMFEAT:
> ++	case CRIOGET:
> ++	case CIOCFSESSION:
> ++	case CIOCGSESSINFO:
> ++		return cryptodev_ioctl(file, cmd, arg_);
> ++
> ++	case COMPAT_CIOCGSESSION:
> ++		if (unlikely(copy_from_user(&compat_sop, arg,
> ++					    sizeof(compat_sop))))
> ++			return -EFAULT;
> ++		compat_to_session_op(&compat_sop, &sop);
> ++
> ++		ret = crypto_create_session(fcr, &sop);
> ++		if (unlikely(ret))
> ++			return ret;
> ++
> ++		session_op_to_compat(&sop, &compat_sop);
> ++		ret = copy_to_user(arg, &compat_sop, sizeof(compat_sop));
> ++		if (unlikely(ret)) {
> ++			crypto_finish_session(fcr, sop.ses);
> ++			return -EFAULT;
> ++		}
> ++		return ret;
> ++
> ++	case COMPAT_CIOCCRYPT:
> ++		ret = compat_kcop_from_user(&kcop, fcr, arg);
> ++		if (unlikely(ret))
> ++			return ret;
> ++
> ++		ret = crypto_run(fcr, &kcop);
> ++		if (unlikely(ret))
> ++			return ret;
> ++
> ++		return compat_kcop_to_user(&kcop, fcr, arg);
> ++#ifdef ENABLE_ASYNC
> ++	case COMPAT_CIOCASYNCCRYPT:
> ++		if (unlikely(ret = compat_kcop_from_user(&kcop, fcr, arg)))
> ++			return ret;
> ++
> ++		return crypto_async_run(pcr, &kcop);
> ++	case COMPAT_CIOCASYNCFETCH:
> ++		ret = crypto_async_fetch(pcr, &kcop);
> ++		if (unlikely(ret))
> ++			return ret;
> ++
> ++		return compat_kcop_to_user(&kcop, fcr, arg);
> ++#endif
> ++	default:
> ++		return -EINVAL;
> ++	}
> ++}
> ++
> ++#endif /* CONFIG_COMPAT */
> ++
> ++static unsigned int cryptodev_poll(struct file *file, poll_table *wait)
> ++{
> ++	struct crypt_priv *pcr = file->private_data;
> ++	int ret = 0;
> ++
> ++	poll_wait(file, &pcr->user_waiter, wait);
> ++
> ++	if (!list_empty_careful(&pcr->done.list))
> ++		ret |= POLLIN | POLLRDNORM;
> ++	if (!list_empty_careful(&pcr->free.list) || pcr->itemcount < MAX_COP_RINGSIZE)
> ++		ret |= POLLOUT | POLLWRNORM;
> ++
> ++	return ret;
> ++}
> ++
> ++static const struct file_operations cryptodev_fops = {
> ++	.owner = THIS_MODULE,
> ++	.open = cryptodev_open,
> ++	.release = cryptodev_release,
> ++	.unlocked_ioctl = cryptodev_ioctl,
> ++#ifdef CONFIG_COMPAT
> ++	.compat_ioctl = cryptodev_compat_ioctl,
> ++#endif /* CONFIG_COMPAT */
> ++	.poll = cryptodev_poll,
> ++};
> ++
> ++static struct miscdevice cryptodev = {
> ++	.minor = MISC_DYNAMIC_MINOR,
> ++	.name = "crypto",
> ++	.fops = &cryptodev_fops,
> ++	.mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH,
> ++};
> ++
> ++static int __init
> ++cryptodev_register(void)
> ++{
> ++	int rc;
> ++
> ++	rc = misc_register(&cryptodev);
> ++	if (unlikely(rc)) {
> ++		pr_err(PFX "registration of /dev/crypto failed\n");
> ++		return rc;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++static void __exit
> ++cryptodev_deregister(void)
> ++{
> ++	misc_deregister(&cryptodev);
> ++}
> ++
> ++/* ====== Module init/exit ====== */
> ++static struct ctl_table verbosity_ctl_dir[] = {
> ++	{
> ++		.procname       = "cryptodev_verbosity",
> ++		.data           = &cryptodev_verbosity,
> ++		.maxlen         = sizeof(int),
> ++		.mode           = 0644,
> ++		.proc_handler   = proc_dointvec,
> ++	},
> ++	{0, },
> ++};
> ++
> ++static struct ctl_table verbosity_ctl_root[] = {
> ++	{
> ++		.procname       = "ioctl",
> ++		.mode           = 0555,
> ++		.child          = verbosity_ctl_dir,
> ++	},
> ++	{0, },
> ++};
> ++static struct ctl_table_header *verbosity_sysctl_header;
> ++static int __init init_cryptodev(void)
> ++{
> ++	int rc;
> ++
> ++	cryptodev_wq = create_workqueue("cryptodev_queue");
> ++	if (unlikely(!cryptodev_wq)) {
> ++		pr_err(PFX "failed to allocate the cryptodev workqueue\n");
> ++		return -EFAULT;
> ++	}
> ++
> ++	rc = cryptodev_register();
> ++	if (unlikely(rc)) {
> ++		destroy_workqueue(cryptodev_wq);
> ++		return rc;
> ++	}
> ++
> ++	verbosity_sysctl_header = register_sysctl_table(verbosity_ctl_root);
> ++
> ++	pr_info(PFX "driver %s loaded.\n", VERSION);
> ++
> ++	return 0;
> ++}
> ++
> ++static void __exit exit_cryptodev(void)
> ++{
> ++	flush_workqueue(cryptodev_wq);
> ++	destroy_workqueue(cryptodev_wq);
> ++
> ++	if (verbosity_sysctl_header)
> ++		unregister_sysctl_table(verbosity_sysctl_header);
> ++
> ++	cryptodev_deregister();
> ++	pr_info(PFX "driver unloaded.\n");
> ++}
> ++
> ++module_init(init_cryptodev);
> ++module_exit(exit_cryptodev);
> ++
> +diff --git a/crypto/cryptodev/lib/Makefile b/crypto/cryptodev/lib/Makefile
> +new file mode 100644
> +index 0000000..af87795
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/Makefile
> +@@ -0,0 +1,15 @@
> ++CFLAGS=-g -O2 -Wall
> ++
> ++all: benchmark
> ++
> ++benchmark: main.c libthreshold.a
> ++	gcc $(CFLAGS) -DDEBUG -o $@ $^ -lssl libthreshold.a
> ++
> ++.o:
> ++	gcc $(CCFLAGS) -c $< -o $@
> ++
> ++libthreshold.a: benchmark.o hash.o threshold.o combo.o
> ++	ar  rcs $@ $^
> ++
> ++clean:
> ++	rm -f *.o *~ benchmark libthreshold.a
> +diff --git a/crypto/cryptodev/lib/benchmark.c b/crypto/cryptodev/lib/benchmark.c
> +new file mode 100644
> +index 0000000..a04efbc
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/benchmark.c
> +@@ -0,0 +1,88 @@
> ++/*
> ++ * Copyright (C) 2011 Free Software Foundation, Inc.
> ++ *
> ++ * This file is part of GnuTLS.
> ++ *
> ++ * GnuTLS is free software: you can redistribute it and/or modify
> ++ * it under the terms of the GNU General Public License as published by
> ++ * the Free Software Foundation, either version 3 of the License, or
> ++ * (at your option) any later version.
> ++ *
> ++ * GnuTLS 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, see <http://www.gnu.org/licenses/>.
> ++ */
> ++
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <signal.h>
> ++#include <sys/time.h>
> ++#include <time.h>
> ++#include <unistd.h>
> ++#include "benchmark.h"
> ++
> ++int benchmark_must_finish = 0;
>   +
> -+	return fill_kcop_from_cop(kcop, fcr);
> ++static void
> ++alarm_handler (int signo)
> ++{
> ++  benchmark_must_finish = 1;
>   +}
>   +
> -+static int kcop_to_user(struct kernel_crypt_op *kcop,
> -+			struct fcrypt *fcr, void __user *arg)
> ++int start_benchmark(struct benchmark_st * st)
>   +{
> -+	int ret;
> ++  int ret;
> ++  struct itimerval timer;
>   +
> -+	ret = fill_cop_from_kcop(kcop, fcr);
> -+	if (unlikely(ret)) {
> -+		dprintk(1, KERN_ERR, "Error in fill_cop_from_kcop\n");
> -+		return ret;
> -+	}
> ++  memset(st, 0, sizeof(*st));
>   +
> -+	if (unlikely(copy_to_user(arg, &kcop->cop, sizeof(kcop->cop)))) {
> -+		dprintk(1, KERN_ERR, "Cannot copy to userspace\n");
> -+		return -EFAULT;
> -+	}
> -+	return 0;
> -+}
> ++  st->old_handler = signal (SIGPROF, alarm_handler);
>   +
> -+static inline void tfm_info_to_alg_info(struct alg_info *dst, struct crypto_tfm *tfm)
> -+{
> -+	snprintf(dst->cra_name, CRYPTODEV_MAX_ALG_NAME,
> -+			"%s", crypto_tfm_alg_name(tfm));
> -+	snprintf(dst->cra_driver_name, CRYPTODEV_MAX_ALG_NAME,
> -+			"%s", crypto_tfm_alg_driver_name(tfm));
> ++  ret = gettimeofday (&st->start, NULL);
> ++  if (ret < 0) {
> ++    perror("gettimeofday");
> ++    return -1;
> ++  }
> ++
> ++  benchmark_must_finish = 0;
> ++
> ++  memset(&timer, 0, sizeof(timer));
> ++  timer.it_value.tv_sec = 0;
> ++  timer.it_value.tv_usec = 100*1000;
> ++
> ++  ret = setitimer(ITIMER_PROF, &timer, NULL);
> ++  if (ret < 0) {
> ++    perror("setitimer");
> ++    return -1;
> ++  }
> ++
> ++  return 0;
>   +}
>   +
> -+static unsigned int is_known_accelerated(struct crypto_tfm *tfm)
> ++/* Returns -1 on error or 0 on success.
> ++ * elapsed: the elapsed time in milliseconds
> ++ */
> ++int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed)
>   +{
> -+const char* name = crypto_tfm_alg_driver_name(tfm);
> ++  unsigned long msecs;
> ++  struct timeval stop;
> ++  int ret;
>   +
> -+	if (name == NULL)
> -+	  return 1; /* assume accelerated */
> -+
> -+	if (strstr(name, "-talitos"))
> -+	  return 1;
> -+	else if (strncmp(name, "mv-", 3) == 0)
> -+	  return 1;
> -+	else if (strstr(name, "geode"))
> -+	  return 1;
> -+	else if (strstr(name, "hifn"))
> -+	  return 1;
> -+	else if (strstr(name, "-ixp4xx"))
> -+	  return 1;
> -+	else if (strstr(name, "-omap"))
> -+	  return 1;
> -+	else if (strstr(name, "-picoxcell"))
> -+	  return 1;
> -+	else if (strstr(name, "-s5p"))
> -+	  return 1;
> -+	else if (strstr(name, "-ppc4xx"))
> -+	  return 1;
> -+	else if (strstr(name, "-caam"))
> -+	  return 1;
> -+	else if (strstr(name, "-n2"))
> -+	  return 1;
> ++  signal(SIGPROF, st->old_handler);
>   +
> -+	return 0;
> ++  ret = gettimeofday (&stop, NULL);
> ++  if (ret < 0)
> ++    return -1;
> ++
> ++  msecs = (stop.tv_sec * 1000 + stop.tv_usec / 1000 -
> ++          (st->start.tv_sec * 1000 + st->start.tv_usec / (1000)));
> ++
> ++  if (elapsed) *elapsed = msecs;
> ++
> ++  return 0;
>   +}
>   +
> -+static int get_session_info(struct fcrypt *fcr, struct session_info_op *siop)
> +diff --git a/crypto/cryptodev/lib/benchmark.h b/crypto/cryptodev/lib/benchmark.h
> +new file mode 100644
> +index 0000000..173552e
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/benchmark.h
> +@@ -0,0 +1,18 @@
> ++#include <sys/time.h>
> ++#include <time.h>
> ++#include <sys/time.h>
> ++#include <signal.h>
> ++
> ++typedef void (*sighandler_t)(int);
> ++
> ++struct benchmark_st
>   +{
> -+	struct csession *ses_ptr;
> -+	struct crypto_tfm *tfm;
> ++  struct timeval start;
> ++  sighandler_t old_handler;
> ++};
>   +
> -+	/* this also enters ses_ptr->sem */
> -+	ses_ptr = crypto_get_session_by_sid(fcr, siop->ses);
> -+	if (unlikely(!ses_ptr)) {
> -+		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", siop->ses);
> -+		return -EINVAL;
> -+	}
> ++extern int benchmark_must_finish;
>   +
> -+	siop->flags = 0;
> ++int start_benchmark(struct benchmark_st * st);
> ++int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed);
>   +
> -+	if (ses_ptr->cdata.init) {
> -+		if (ses_ptr->cdata.aead == 0) {
> -+			tfm = crypto_ablkcipher_tfm(ses_ptr->cdata.async.s);
> -+		} else {
> -+			tfm = crypto_aead_tfm(ses_ptr->cdata.async.as);
> -+		}
> -+		tfm_info_to_alg_info(&siop->cipher_info, tfm);
> -+#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY
> -+		if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY)
> -+			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> -+#else
> -+		if (is_known_accelerated(tfm))
> -+			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> +diff --git a/crypto/cryptodev/lib/combo.c b/crypto/cryptodev/lib/combo.c
> +new file mode 100644
> +index 0000000..b26da0a
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/combo.c
> +@@ -0,0 +1,171 @@
> ++/*
> ++ * Demo on how to use /dev/crypto device for ciphering.
> ++ *
> ++ * Placed under public domain.
> ++ *
> ++ */
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include "benchmark.h"
> ++#include "hash.h"
> ++
> ++int aead_ctx_init(struct cryptodev_ctx* ctx, int cipher, int hash, void* key, int key_size, int cfd)
> ++{
> ++#ifdef CIOCGSESSINFO
> ++	struct session_info_op siop;
>   +#endif
> ++
> ++	memset(ctx, 0, sizeof(*ctx));
> ++	ctx->cfd = cfd;
> ++
> ++	ctx->sess.mac = hash;
> ++	ctx->sess.cipher = cipher;
> ++	ctx->sess.key = key;
> ++	ctx->sess.keylen = key_size;
> ++
> ++	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
> ++		perror("ioctl(CIOCGSESSION)");
> ++		return -1;
>   +	}
> -+	if (ses_ptr->hdata.init) {
> -+		tfm = crypto_ahash_tfm(ses_ptr->hdata.async.s);
> -+		tfm_info_to_alg_info(&siop->hash_info, tfm);
> -+#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY
> -+		if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY)
> -+			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> -+#else
> -+		if (is_known_accelerated(tfm))
> -+			siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY;
> ++
> ++#ifdef CIOCGSESSINFO
> ++	memset(&siop, 0, sizeof(siop));
> ++	siop.ses = ctx->sess.ses;
> ++	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
> ++		perror("ioctl(CIOCGSESSINFO)");
> ++		return -1;
> ++	}
> ++#ifdef DEBUG
> ++	printf("Got %s-%s with drivers %s and %s\n",
> ++			siop.cipher_info.cra_name, siop.hash_info.cra_name,
> ++			siop.cipher_info.cra_driver_name, siop.hash_info.cra_driver_name);
> ++#endif
> ++	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/
> ++	ctx->alignmask = siop.alignmask;
>   +#endif
> ++	return 0;
> ++}
> ++
> ++void aead_ctx_deinit(struct cryptodev_ctx* ctx)
> ++{
> ++	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
> ++		perror("ioctl(CIOCFSESSION)");
>   +	}
> ++}
>   +
> -+	siop->alignmask = ses_ptr->alignmask;
> ++int
> ++aead_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size, void* digest)
> ++{
> ++	struct crypt_auth_op cryp;
> ++
> ++	memset(&cryp, 0, sizeof(cryp));
> ++
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.len = size;
> ++	cryp.iv = (void*)iv;
> ++	cryp.iv_len = 16;
> ++	cryp.src = (void*)plaintext;
> ++	cryp.dst = (void*)ciphertext;
> ++	cryp.flags = COP_FLAG_AEAD_TLS_TYPE;
> ++
> ++	if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCAUTHCRYPT)");
> ++		return -1;
> ++	}
>   +
> -+	crypto_put_session(ses_ptr);
>   +	return 0;
>   +}
>   +
> -+static long
> -+cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
> ++static const int sizes[] = {64, 256, 512, 1024, 4096, 16*1024};
> ++
> ++
> ++int aead_test(int cipher, int mac, void* ukey, int ukey_size,
> ++		void* user_ctx, void (*user_combo)(void* user_ctx, void* plaintext, void* ciphertext, int size, void* res))
>   +{
> -+	void __user *arg = (void __user *)arg_;
> -+	int __user *p = arg;
> -+	struct session_op sop;
> -+	struct kernel_crypt_op kcop;
> -+	struct kernel_crypt_auth_op kcaop;
> -+	struct crypt_priv *pcr = filp->private_data;
> -+	struct fcrypt *fcr;
> -+	struct session_info_op siop;
> -+	uint32_t ses;
> -+	int ret, fd;
> ++	int cfd = -1, i, ret;
> ++	struct cryptodev_ctx ctx;
> ++	uint8_t digest[AALG_MAX_RESULT_LEN];
> ++	char text[16*1024];
> ++	char ctext[16*1024];
> ++	char iv[16];
> ++	unsigned long elapsed, counted;
> ++	double t1, t2;
> ++	struct benchmark_st bst;
>   +
> -+	if (unlikely(!pcr))
> -+		BUG();
> ++	/* Open the crypto device */
> ++	cfd = open("/dev/crypto", O_RDWR, 0);
> ++	if (cfd < 0) {
> ++		perror("open(/dev/crypto)");
> ++		return -1;
> ++	}
>   +
> -+	fcr = &pcr->fcrypt;
> ++	aead_ctx_init(&ctx, cipher, mac, ukey, ukey_size, cfd);
>   +
> -+	switch (cmd) {
> -+	case CIOCASYMFEAT:
> -+		return put_user(0, p);
> -+	case CRIOGET:
> -+		fd = clonefd(filp);
> -+		ret = put_user(fd, p);
> -+		if (unlikely(ret)) {
> -+			sys_close(fd);
> -+			return ret;
> ++	for (i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
> ++		counted = 0;
> ++		ret = start_benchmark(&bst);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
>   +		}
> -+		return ret;
> -+	case CIOCGSESSION:
> -+		if (unlikely(copy_from_user(&sop, arg, sizeof(sop))))
> -+			return -EFAULT;
>   +
> -+		ret = crypto_create_session(fcr, &sop);
> -+		if (unlikely(ret))
> -+			return ret;
> -+		ret = copy_to_user(arg, &sop, sizeof(sop));
> -+		if (unlikely(ret)) {
> -+			crypto_finish_session(fcr, sop.ses);
> -+			return -EFAULT;
> -+		}
> -+		return ret;
> -+	case CIOCFSESSION:
> -+		ret = get_user(ses, (uint32_t __user *)arg);
> -+		if (unlikely(ret))
> -+			return ret;
> -+		ret = crypto_finish_session(fcr, ses);
> -+		return ret;
> -+	case CIOCGSESSINFO:
> -+		if (unlikely(copy_from_user(&siop, arg, sizeof(siop))))
> -+			return -EFAULT;
> ++		do {
> ++			if (aead_encrypt(&ctx, iv, text, text, sizes[i], digest) < 0)
> ++				return -2;
> ++			counted += sizes[i];
> ++		} while(benchmark_must_finish==0);
>   +
> -+		ret = get_session_info(fcr, &siop);
> -+		if (unlikely(ret))
> -+			return ret;
> -+		return copy_to_user(arg, &siop, sizeof(siop));
> -+	case CIOCCRYPT:
> -+		if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) {
> -+			dprintk(1, KERN_WARNING, "Error copying from user\n");
> -+			return ret;
> ++		ret = stop_benchmark(&bst, &elapsed);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
>   +		}
>   +
> -+		ret = crypto_run(fcr, &kcop);
> -+		if (unlikely(ret)) {
> -+			dprintk(1, KERN_WARNING, "Error in crypto_run\n");
> -+			return ret;
> -+		}
> ++		t1 = (double)counted/(double)elapsed;
>   +
> -+		return kcop_to_user(&kcop, fcr, arg);
> -+	case CIOCAUTHCRYPT:
> -+		if (unlikely(ret = kcaop_from_user(&kcaop, fcr, arg))) {
> -+			dprintk(1, KERN_WARNING, "Error copying from user\n");
> -+			return ret;
> ++		/* now check the user function */
> ++		counted = 0;
> ++		ret = start_benchmark(&bst);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
>   +		}
>   +
> -+		ret = crypto_auth_run(fcr, &kcaop);
> -+		if (unlikely(ret)) {
> -+			dprintk(1, KERN_WARNING, "Error in crypto_auth_run\n");
> -+			return ret;
> ++		do {
> ++			user_combo(user_ctx, text, ctext, sizes[i], digest);
> ++			counted += sizes[i];
> ++		} while(benchmark_must_finish==0);
> ++
> ++		ret = stop_benchmark(&bst, &elapsed);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
>   +		}
> -+		return kcaop_to_user(&kcaop, fcr, arg);
> -+#ifdef ENABLE_ASYNC
> -+	case CIOCASYNCCRYPT:
> -+		if (unlikely(ret = kcop_from_user(&kcop, fcr, arg)))
> -+			return ret;
>   +
> -+		return crypto_async_run(pcr, &kcop);
> -+	case CIOCASYNCFETCH:
> -+		ret = crypto_async_fetch(pcr, &kcop);
> -+		if (unlikely(ret))
> -+			return ret;
> ++		t2 = (double)counted/(double)elapsed;
>   +
> -+		return kcop_to_user(&kcop, fcr, arg);
> ++#ifdef DEBUG
> ++		printf("%d: kernel: %.4f bytes/msec, user: %.4f bytes/msec\n", sizes[i], t1, t2);
>   +#endif
> -+	default:
> -+		return -EINVAL;
> ++		if (t1 > t2) {
> ++			ret = sizes[i];
> ++			goto finish;
> ++		}
>   +	}
> -+}
> -+
> -+/* compatibility code for 32bit userlands */
> -+#ifdef CONFIG_COMPAT
> -+
> -+static inline void
> -+compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
> -+{
> -+	sop->cipher = compat->cipher;
> -+	sop->mac = compat->mac;
> -+	sop->keylen = compat->keylen;
> -+
> -+	sop->key       = compat_ptr(compat->key);
> -+	sop->mackeylen = compat->mackeylen;
> -+	sop->mackey    = compat_ptr(compat->mackey);
> -+	sop->ses       = compat->ses;
> -+}
>   +
> -+static inline void
> -+session_op_to_compat(struct session_op *sop, struct compat_session_op *compat)
> -+{
> -+	compat->cipher = sop->cipher;
> -+	compat->mac = sop->mac;
> -+	compat->keylen = sop->keylen;
> ++	ret = -1;
> ++finish:
> ++	aead_ctx_deinit(&ctx);
>   +
> -+	compat->key       = ptr_to_compat(sop->key);
> -+	compat->mackeylen = sop->mackeylen;
> -+	compat->mackey    = ptr_to_compat(sop->mackey);
> -+	compat->ses       = sop->ses;
> ++	/* Close the original descriptor */
> ++	if (close(cfd)) {
> ++		perror("close(cfd)");
> ++		return 1;
> ++	}
> ++	return ret;
>   +}
> +diff --git a/crypto/cryptodev/lib/hash.c b/crypto/cryptodev/lib/hash.c
> +new file mode 100644
> +index 0000000..386fd7e
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/hash.c
> +@@ -0,0 +1,161 @@
> ++/*
> ++ * Demo on how to use /dev/crypto device for ciphering.
> ++ *
> ++ * Placed under public domain.
> ++ *
> ++ */
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include "hash.h"
> ++#include "benchmark.h"
>   +
> -+static inline void
> -+compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop)
> ++int hash_ctx_init(struct cryptodev_ctx* ctx, int hash, int cfd)
>   +{
> -+	cop->ses = compat->ses;
> -+	cop->op = compat->op;
> -+	cop->flags = compat->flags;
> -+	cop->len = compat->len;
> ++#ifdef CIOCGSESSINFO
> ++	struct session_info_op siop;
> ++#endif
>   +
> -+	cop->src = compat_ptr(compat->src);
> -+	cop->dst = compat_ptr(compat->dst);
> -+	cop->mac = compat_ptr(compat->mac);
> -+	cop->iv  = compat_ptr(compat->iv);
> -+}
> ++	memset(ctx, 0, sizeof(*ctx));
> ++	ctx->cfd = cfd;
>   +
> -+static inline void
> -+crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat)
> -+{
> -+	compat->ses = cop->ses;
> -+	compat->op = cop->op;
> -+	compat->flags = cop->flags;
> -+	compat->len = cop->len;
> ++	ctx->sess.mac = hash;
>   +
> -+	compat->src = ptr_to_compat(cop->src);
> -+	compat->dst = ptr_to_compat(cop->dst);
> -+	compat->mac = ptr_to_compat(cop->mac);
> -+	compat->iv  = ptr_to_compat(cop->iv);
> ++	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
> ++		perror("ioctl(CIOCGSESSION)");
> ++		return -1;
> ++	}
> ++
> ++#ifdef CIOCGSESSINFO
> ++	memset(&siop, 0, sizeof(siop));
> ++	siop.ses = ctx->sess.ses;
> ++	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
> ++		perror("ioctl(CIOCGSESSINFO)");
> ++		return -1;
> ++	}
> ++#ifdef DEBUG
> ++	printf("Got %s with driver %s\n",
> ++			siop.hash_info.cra_name, siop.hash_info.cra_driver_name);
> ++#endif
> ++	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/
> ++	ctx->alignmask = siop.alignmask;
> ++#endif
> ++	return 0;
>   +}
>   +
> -+static int compat_kcop_from_user(struct kernel_crypt_op *kcop,
> -+                                 struct fcrypt *fcr, void __user *arg)
> ++void hash_ctx_deinit(struct cryptodev_ctx* ctx)
>   +{
> -+	struct compat_crypt_op compat_cop;
> -+
> -+	if (unlikely(copy_from_user(&compat_cop, arg, sizeof(compat_cop))))
> -+		return -EFAULT;
> -+	compat_to_crypt_op(&compat_cop, &kcop->cop);
> -+
> -+	return fill_kcop_from_cop(kcop, fcr);
> ++	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
> ++		perror("ioctl(CIOCFSESSION)");
> ++	}
>   +}
>   +
> -+static int compat_kcop_to_user(struct kernel_crypt_op *kcop,
> -+                                 struct fcrypt *fcr, void __user *arg)
> ++int
> ++hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest)
>   +{
> -+	int ret;
> -+	struct compat_crypt_op compat_cop;
> ++	struct crypt_op cryp;
>   +
> -+	ret = fill_cop_from_kcop(kcop, fcr);
> -+	if (unlikely(ret)) {
> -+		dprintk(1, KERN_WARNING, "Error in fill_cop_from_kcop\n");
> -+		return ret;
> -+	}
> -+	crypt_op_to_compat(&kcop->cop, &compat_cop);
> ++	memset(&cryp, 0, sizeof(cryp));
>   +
> -+	if (unlikely(copy_to_user(arg, &compat_cop, sizeof(compat_cop)))) {
> -+		dprintk(1, KERN_WARNING, "Error copying to user\n");
> -+		return -EFAULT;
> ++	/* Encrypt data.in to data.encrypted */
> ++	cryp.ses = ctx->sess.ses;
> ++	cryp.len = size;
> ++	cryp.src = (void*)text;
> ++	cryp.mac = digest;
> ++	if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
> ++		perror("ioctl(CIOCCRYPT)");
> ++		return -1;
>   +	}
> ++
>   +	return 0;
>   +}
>   +
> -+static long
> -+cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
> ++static const int sizes[] = {64, 256, 512, 1024, 4096, 16*1024};
> ++
> ++/* Worst case running time: around 1.2 secs
> ++ */
> ++int hash_test(int algo, void (*user_hash)(void* text, int size, void* res))
>   +{
> -+	void __user *arg = (void __user *)arg_;
> -+	struct crypt_priv *pcr = file->private_data;
> -+	struct fcrypt *fcr;
> -+	struct session_op sop;
> -+	struct compat_session_op compat_sop;
> -+	struct kernel_crypt_op kcop;
> -+	int ret;
> ++	int cfd = -1, i, ret;
> ++	struct cryptodev_ctx ctx;
> ++	uint8_t digest[AALG_MAX_RESULT_LEN];
> ++	char text[16*1024];
> ++	unsigned long elapsed, counted;
> ++	double t1, t2;
> ++	struct benchmark_st bst;
>   +
> -+	if (unlikely(!pcr))
> -+		BUG();
> ++	/* Open the crypto device */
> ++	cfd = open("/dev/crypto", O_RDWR, 0);
> ++	if (cfd < 0) {
> ++		perror("open(/dev/crypto)");
> ++		return -1;
> ++	}
>   +
> -+	fcr = &pcr->fcrypt;
> ++	hash_ctx_init(&ctx, algo, cfd);
>   +
> -+	switch (cmd) {
> -+	case CIOCASYMFEAT:
> -+	case CRIOGET:
> -+	case CIOCFSESSION:
> -+	case CIOCGSESSINFO:
> -+		return cryptodev_ioctl(file, cmd, arg_);
> ++	for (i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
> ++		counted = 0;
> ++		ret = start_benchmark(&bst);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
> ++		}
>   +
> -+	case COMPAT_CIOCGSESSION:
> -+		if (unlikely(copy_from_user(&compat_sop, arg,
> -+					    sizeof(compat_sop))))
> -+			return -EFAULT;
> -+		compat_to_session_op(&compat_sop, &sop);
> ++		do {
> ++			hash(&ctx, text, sizes[i], digest);
> ++			counted += sizes[i];
> ++		} while(benchmark_must_finish==0);
>   +
> -+		ret = crypto_create_session(fcr, &sop);
> -+		if (unlikely(ret))
> -+			return ret;
> ++		ret = stop_benchmark(&bst, &elapsed);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
> ++		}
> ++		t1 = (double)counted/(double)elapsed;
>   +
> -+		session_op_to_compat(&sop, &compat_sop);
> -+		ret = copy_to_user(arg, &compat_sop, sizeof(compat_sop));
> -+		if (unlikely(ret)) {
> -+			crypto_finish_session(fcr, sop.ses);
> -+			return -EFAULT;
> ++		/* now check the user function */
> ++		counted = 0;
> ++		ret = start_benchmark(&bst);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
>   +		}
> -+		return ret;
>   +
> -+	case COMPAT_CIOCCRYPT:
> -+		ret = compat_kcop_from_user(&kcop, fcr, arg);
> -+		if (unlikely(ret))
> -+			return ret;
>   +
> -+		ret = crypto_run(fcr, &kcop);
> -+		if (unlikely(ret))
> -+			return ret;
> ++		do {
> ++			user_hash(text, sizes[i], digest);
> ++			counted += sizes[i];
> ++		} while(benchmark_must_finish==0);
>   +
> -+		return compat_kcop_to_user(&kcop, fcr, arg);
> -+#ifdef ENABLE_ASYNC
> -+	case COMPAT_CIOCASYNCCRYPT:
> -+		if (unlikely(ret = compat_kcop_from_user(&kcop, fcr, arg)))
> -+			return ret;
> ++		ret = stop_benchmark(&bst, &elapsed);
> ++		if (ret < 0) {
> ++			ret = -1;
> ++			goto finish;
> ++		}
>   +
> -+		return crypto_async_run(pcr, &kcop);
> -+	case COMPAT_CIOCASYNCFETCH:
> -+		ret = crypto_async_fetch(pcr, &kcop);
> -+		if (unlikely(ret))
> -+			return ret;
> ++		t2 = (double)counted/(double)elapsed;
>   +
> -+		return compat_kcop_to_user(&kcop, fcr, arg);
> ++		if (t1 > t2) {
> ++			ret = sizes[i];
> ++			goto finish;
> ++		}
> ++#ifdef DEBUG
> ++		printf("%d: kernel: %.4f bytes/msec, user: %.4f bytes/msec\n", sizes[i], t1, t2);
>   +#endif
> -+	default:
> -+		return -EINVAL;
>   +	}
> -+}
> -+
> -+#endif /* CONFIG_COMPAT */
> -+
> -+static unsigned int cryptodev_poll(struct file *file, poll_table *wait)
> -+{
> -+	struct crypt_priv *pcr = file->private_data;
> -+	int ret = 0;
>   +
> -+	poll_wait(file, &pcr->user_waiter, wait);
> -+
> -+	if (!list_empty_careful(&pcr->done.list))
> -+		ret |= POLLIN | POLLRDNORM;
> -+	if (!list_empty_careful(&pcr->free.list) || pcr->itemcount < MAX_COP_RINGSIZE)
> -+		ret |= POLLOUT | POLLWRNORM;
> ++	ret = -1;
> ++finish:
> ++	hash_ctx_deinit(&ctx);
>   +
> ++	/* Close the original descriptor */
> ++	if (close(cfd)) {
> ++		perror("close(cfd)");
> ++		return 1;
> ++	}
>   +	return ret;
>   +}
>   +
> -+static const struct file_operations cryptodev_fops = {
> -+	.owner = THIS_MODULE,
> -+	.open = cryptodev_open,
> -+	.release = cryptodev_release,
> -+	.unlocked_ioctl = cryptodev_ioctl,
> -+#ifdef CONFIG_COMPAT
> -+	.compat_ioctl = cryptodev_compat_ioctl,
> -+#endif /* CONFIG_COMPAT */
> -+	.poll = cryptodev_poll,
> -+};
> +diff --git a/crypto/cryptodev/lib/hash.h b/crypto/cryptodev/lib/hash.h
> +new file mode 100644
> +index 0000000..7c32cea
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/hash.h
> +@@ -0,0 +1,20 @@
> ++#ifndef HASH_H
> ++# define HASH_H
>   +
> -+static struct miscdevice cryptodev = {
> -+	.minor = MISC_DYNAMIC_MINOR,
> -+	.name = "crypto",
> -+	.fops = &cryptodev_fops,
> -+	.mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH,
> ++#include <stdint.h>
> ++
> ++struct cryptodev_ctx {
> ++	int cfd;
> ++	struct session_op sess;
> ++	uint16_t alignmask;
>   +};
>   +
> -+static int __init
> -+cryptodev_register(void)
> ++int hash_ctx_init(struct cryptodev_ctx* ctx, int hash, int cfd);
> ++void hash_ctx_deinit(struct cryptodev_ctx* ctx);
> ++int hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest);
> ++int hash_test(int algo, void (*user_hash)(void* text, int size, void* res));
> ++
> ++int aead_test(int cipher, int mac, void* ukey, int ukey_size,
> ++		void* user_ctx, void (*user_combo)(void* user_ctx, void* plaintext, void* ciphertext, int size, void* res));
> ++
> ++#endif
> +diff --git a/crypto/cryptodev/lib/main.c b/crypto/cryptodev/lib/main.c
> +new file mode 100644
> +index 0000000..443779a
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/main.c
> +@@ -0,0 +1,28 @@
> ++/*
> ++ * Demo on how to use /dev/crypto device for ciphering.
> ++ *
> ++ * Placed under public domain.
> ++ *
> ++ */
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include "threshold.h"
> ++
> ++int main()
>   +{
> -+	int rc;
> ++int ret;
>   +
> -+	rc = misc_register(&cryptodev);
> -+	if (unlikely(rc)) {
> -+		printk(KERN_ERR PFX "registration of /dev/crypto failed\n");
> -+		return rc;
> -+	}
> ++	ret = get_sha1_threshold();
> ++	if (ret > 0)
> ++		printf("SHA1 in kernel outperforms user-space after %d input bytes\n", ret);
> ++
> ++	ret = get_aes_sha1_threshold();
> ++	if (ret > 0)
> ++		printf("AES-SHA1 in kernel outperforms user-space after %d input bytes\n", ret);
>   +
>   +	return 0;
>   +}
> +diff --git a/crypto/cryptodev/lib/threshold.c b/crypto/cryptodev/lib/threshold.c
> +new file mode 100644
> +index 0000000..b002d58
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/threshold.c
> +@@ -0,0 +1,61 @@
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <crypto/cryptodev.h>
> ++#include <openssl/aes.h>
> ++#include <openssl/engine.h>
> ++#include <openssl/hmac.h>
> ++#include <openssl/evp.h>
> ++#include "hash.h"
> ++#include "threshold.h"
>   +
> -+static void __exit
> -+cryptodev_deregister(void)
> ++void sha_hash(void* text, int size, void* digest)
>   +{
> -+	misc_deregister(&cryptodev);
> ++SHA_CTX ctx;
> ++
> ++	SHA_Init(&ctx);
> ++
> ++	SHA_Update(&ctx, text, size);
> ++
> ++	SHA_Final(digest, &ctx);
>   +}
>   +
> -+/* ====== Module init/exit ====== */
> -+static int __init init_cryptodev(void)
> ++void aes_sha_combo(void* ctx, void* plaintext, void* ciphertext, int size, void* tag)
>   +{
> -+	int rc;
> ++uint8_t iv[16];
> ++AES_KEY* key = ctx;
> ++HMAC_CTX hctx;
> ++unsigned int rlen = 20;
>   +
> -+	cryptodev_wq = create_workqueue("cryptodev_queue");
> -+	if (unlikely(!cryptodev_wq)) {
> -+		printk(KERN_ERR PFX "failed to allocate the cryptodev workqueue\n");
> -+		return -EFAULT;
> -+	}
> ++	HMAC_CTX_init(&hctx);
> ++	HMAC_Init_ex(&hctx, iv, 16, EVP_sha1(), NULL);
>   +
> -+	rc = cryptodev_register();
> -+	if (unlikely(rc)) {
> -+		destroy_workqueue(cryptodev_wq);
> -+		return rc;
> -+	}
> ++	HMAC_Update(&hctx, plaintext, size);
>   +
> -+	printk(KERN_INFO PFX "driver %s loaded.\n", VERSION);
> ++	HMAC_Final(&hctx, tag, &rlen);
> ++	HMAC_CTX_cleanup(&hctx);
>   +
> -+	return 0;
> ++	AES_cbc_encrypt(plaintext, ciphertext, size, key, iv, 1);
>   +}
>   +
> -+static void __exit exit_cryptodev(void)
> ++int get_sha1_threshold()
>   +{
> -+	flush_workqueue(cryptodev_wq);
> -+	destroy_workqueue(cryptodev_wq);
> -+
> -+	cryptodev_deregister();
> -+	printk(KERN_INFO PFX "driver unloaded.\n");
> ++	return hash_test(CRYPTO_SHA1, sha_hash);
>   +}
>   +
> -+module_init(init_cryptodev);
> -+module_exit(exit_cryptodev);
> ++int get_aes_sha1_threshold()
> ++{
> ++AES_KEY key;
> ++uint8_t ukey[16];
> ++
> ++	ENGINE_load_builtin_engines();
> ++        ENGINE_register_all_complete();
>   +
> ++	memset(ukey, 0xaf, sizeof(ukey));
> ++	AES_set_encrypt_key(ukey, 16*8, &key);
> ++
> ++	return aead_test(CRYPTO_AES_CBC, CRYPTO_SHA1, ukey, 16, &key, aes_sha_combo);
> ++}
> ++
> +diff --git a/crypto/cryptodev/lib/threshold.h b/crypto/cryptodev/lib/threshold.h
> +new file mode 100644
> +index 0000000..6c11019
> +--- /dev/null
> ++++ b/crypto/cryptodev/lib/threshold.h
> +@@ -0,0 +1,10 @@
> ++/* Return the number of bytes after which the
> ++ * kernel operation is more efficient to use.
> ++ * If return value is -1, then kernel operation
> ++ * cannot, or shouldn't be used, because it is always
> ++ * slower.
> ++ *
> ++ * Running time ~= 1.2 seconds per call.
> ++ */
> ++int get_sha1_threshold();
> ++int get_aes_sha1_threshold();
>   diff --git a/crypto/cryptodev/main.c b/crypto/cryptodev/main.c
>   new file mode 100644
> -index 0000000..fe6d390
> +index 0000000..57e5c38
>   --- /dev/null
>   +++ b/crypto/cryptodev/main.c
> -@@ -0,0 +1,257 @@
> +@@ -0,0 +1,267 @@
>   +/*
>   + * Driver for /dev/crypto device (aka CryptoDev)
>   + *
>   + * Copyright (c) 2004 Michal Ludvig <mludvig at logix.net.nz>, SuSE Labs
> -+ * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav at gnutls.org>
> ++ * Copyright (c) 2009-2013 Nikos Mavrogiannopoulos <nmav at gnutls.org>
>   + *
>   + * This file is part of linux cryptodev.
>   + *
> @@ -3610,7 +5274,7 @@ index 0000000..fe6d390
>   +	}
>   +	return 0;
>   +out_err:
> -+	dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n", ret);
> ++	derr(0, "CryptoAPI failure: %d", ret);
>   +	return ret;
>   +}
>   +
> @@ -3629,9 +5293,9 @@ index 0000000..fe6d390
>   +	data = (char *)__get_free_page(GFP_KERNEL);
>   +
>   +	if (unlikely(!data)) {
> -+		dprintk(1, KERN_ERR, "Error getting free page.\n");
> ++		derr(1, "Error getting free page.");
>   +		return -ENOMEM;
> -+        }
> ++	}
>   +
>   +	bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
>   +
> @@ -3642,7 +5306,7 @@ index 0000000..fe6d390
>   +		size_t current_len = nbytes > bufsize ? bufsize : nbytes;
>   +
>   +		if (unlikely(copy_from_user(data, src, current_len))) {
> -+		        dprintk(1, KERN_ERR, "Error copying %d bytes from user address %p.\n", (int)current_len, src);
> ++		        derr(1, "Error copying %zu bytes from user address %p.", current_len, src);
>   +			ret = -EFAULT;
>   +			break;
>   +		}
> @@ -3652,13 +5316,13 @@ index 0000000..fe6d390
>   +		ret = hash_n_crypt(ses_ptr, cop, &sg, &sg, current_len);
>   +
>   +		if (unlikely(ret)) {
> -+		        dprintk(1, KERN_ERR, "hash_n_crypt failed.\n");
> ++		        derr(1, "hash_n_crypt failed.");
>   +			break;
> -+                }
> ++		}
>   +
>   +		if (ses_ptr->cdata.init != 0) {
>   +			if (unlikely(copy_to_user(dst, data, current_len))) {
> -+			        dprintk(1, KERN_ERR, "could not copy to user.\n");
> ++			        derr(1, "could not copy to user.");
>   +				ret = -EFAULT;
>   +				break;
>   +			}
> @@ -3686,8 +5350,7 @@ index 0000000..fe6d390
>   +	ret = get_userbuf(ses_ptr, cop->src, cop->len, cop->dst, cop->len,
>   +	                  kcop->task, kcop->mm, &src_sg, &dst_sg);
>   +	if (unlikely(ret)) {
> -+		dprintk(1, KERN_ERR, "Error getting user pages. "
> -+					"Falling back to non zero copy.\n");
> ++		derr(1, "Error getting user pages. Falling back to non zero copy.");
>   +		return __crypto_run_std(ses_ptr, cop);
>   +	}
>   +
> @@ -3704,22 +5367,21 @@ index 0000000..fe6d390
>   +	int ret;
>   +
>   +	if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
> -+		dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
> ++		ddebug(1, "invalid operation op=%u", cop->op);
>   +		return -EINVAL;
>   +	}
>   +
>   +	/* this also enters ses_ptr->sem */
>   +	ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
>   +	if (unlikely(!ses_ptr)) {
> -+		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
> ++		derr(1, "invalid session ID=0x%08X", cop->ses);
>   +		return -EINVAL;
>   +	}
>   +
>   +	if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET)) {
>   +		ret = cryptodev_hash_reset(&ses_ptr->hdata);
>   +		if (unlikely(ret)) {
> -+			dprintk(1, KERN_ERR,
> -+				"error in cryptodev_hash_reset()\n");
> ++			derr(1, "error in cryptodev_hash_reset()");
>   +			goto out_unlock;
>   +		}
>   +	}
> @@ -3728,9 +5390,7 @@ index 0000000..fe6d390
>   +		int blocksize = ses_ptr->cdata.blocksize;
>   +
>   +		if (unlikely(cop->len % blocksize)) {
> -+			dprintk(1, KERN_ERR,
> -+				"data size (%u) isn't a multiple "
> -+				"of block size (%u)\n",
> ++			derr(1, "data size (%u) isn't a multiple of block size (%u)",
>   +				cop->len, blocksize);
>   +			ret = -EINVAL;
>   +			goto out_unlock;
> @@ -3741,6 +5401,20 @@ index 0000000..fe6d390
>   +	}
>   +
>   +	if (likely(cop->len)) {
> ++		if (cop->flags & COP_FLAG_NO_ZC) {
> ++			if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->src, ses_ptr->alignmask))) {
> ++				dwarning(2, "source address %p is not %d byte aligned - disabling zero copy",
> ++						cop->src, ses_ptr->alignmask + 1);
> ++				cop->flags &= ~COP_FLAG_NO_ZC;
> ++			}
> ++
> ++			if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->dst, ses_ptr->alignmask))) {
> ++				dwarning(2, "destination address %p is not %d byte aligned - disabling zero copy",
> ++						cop->dst, ses_ptr->alignmask + 1);
> ++				cop->flags &= ~COP_FLAG_NO_ZC;
> ++			}
> ++		}
> ++
>   +		if (cop->flags & COP_FLAG_NO_ZC)
>   +			ret = __crypto_run_std(ses_ptr, &kcop->cop);
>   +		else
> @@ -3760,7 +5434,7 @@ index 0000000..fe6d390
>   +
>   +		ret = cryptodev_hash_final(&ses_ptr->hdata, kcop->hash_output);
>   +		if (unlikely(ret)) {
> -+			dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n", ret);
> ++			derr(0, "CryptoAPI failure: %d", ret);
>   +			goto out_unlock;
>   +		}
>   +		kcop->digestsize = ses_ptr->hdata.digestsize;
> @@ -7789,10 +9463,10 @@ index 0000000..1d9349e
>   +}
>   diff --git a/crypto/cryptodev/tests/hmac_comp.c b/crypto/cryptodev/tests/hmac_comp.c
>   new file mode 100644
> -index 0000000..451bedb
> +index 0000000..a8709cb
>   --- /dev/null
>   +++ b/crypto/cryptodev/tests/hmac_comp.c
> -@@ -0,0 +1,180 @@
> +@@ -0,0 +1,187 @@
>   +/*
>   + * Compare HMAC results with ones from openssl.
>   + *
> @@ -7833,6 +9507,7 @@ index 0000000..451bedb
>   +	unsigned char iv[BLOCK_SIZE];
>   +	unsigned char mac[AALG_MAX_RESULT_LEN];
>   +
> ++	unsigned char iv_comp[BLOCK_SIZE];
>   +	unsigned char mac_comp[AALG_MAX_RESULT_LEN];
>   +
>   +	struct crypt_op cryp;
> @@ -7844,11 +9519,12 @@ index 0000000..451bedb
>   +	encrypted_comp = malloc(datalen);
>   +	memset(data, datalen & 0xff, datalen);
>   +	memset(encrypted, 0x27, datalen);
> -+	memset(encrypted_comp, 0x27, datalen);
> ++	memset(encrypted_comp, 0x28, datalen);
>   +
>   +	memset(iv, 0x23, sizeof(iv));
> ++	memset(iv_comp, 0x23, sizeof(iv));
>   +	memset(mac, 0, sizeof(mac));
> -+	memset(mac_comp, 0, sizeof(mac_comp));
> ++	memset(mac_comp, 1, sizeof(mac_comp));
>   +
>   +	memset(&cryp, 0, sizeof(cryp));
>   +
> @@ -7860,6 +9536,7 @@ index 0000000..451bedb
>   +	cryp.iv = iv;
>   +	cryp.mac = mac;
>   +	cryp.op = COP_ENCRYPT;
> ++	cryp.flags = COP_FLAG_WRITE_IV;
>   +	if ((ret = ioctl(cfd, CIOCCRYPT, &cryp))) {
>   +		perror("ioctl(CIOCCRYPT)");
>   +		goto out;
> @@ -7867,6 +9544,7 @@ index 0000000..451bedb
>   +
>   +	cryp.dst = encrypted_comp;
>   +	cryp.mac = mac_comp;
> ++	cryp.iv = iv_comp;
>   +
>   +	if ((ret = openssl_cioccrypt(sess, &cryp))) {
>   +		fprintf(stderr, "openssl_cioccrypt() failed!\n");
> @@ -7876,6 +9554,9 @@ index 0000000..451bedb
>   +	if ((ret = memcmp(encrypted, encrypted_comp, cryp.len))) {
>   +		printf("fail for datalen %d, cipher texts do not match!\n", datalen);
>   +	}
> ++	if ((ret = memcmp(iv, iv_comp, BLOCK_SIZE))) {
> ++		printf("fail for datalen %d, updated IVs do not match!\n", datalen);
> ++	}
>   +	if ((ret = memcmp(mac, mac_comp, AALG_MAX_RESULT_LEN))) {
>   +		printf("fail for datalen 0x%x, MACs do not match!\n", datalen);
>   +		printf("wrong mac: ");
> @@ -8846,14 +10527,14 @@ index 0000000..83d49da
>   +#define VERSION "1.6"
>   diff --git a/crypto/cryptodev/zc.c b/crypto/cryptodev/zc.c
>   new file mode 100644
> -index 0000000..884dbab
> +index 0000000..29b0501
>   --- /dev/null
>   +++ b/crypto/cryptodev/zc.c
> -@@ -0,0 +1,217 @@
> +@@ -0,0 +1,208 @@
>   +/*
>   + * Driver for /dev/crypto device (aka CryptoDev)
>   + *
> -+ * Copyright (c) 2009-2011 Nikos Mavrogiannopoulos <nmav at gnutls.org>
> ++ * Copyright (c) 2009-2013 Nikos Mavrogiannopoulos <nmav at gnutls.org>
>   + * Copyright (c) 2010 Phil Sutter
>   + * Copyright (c) 2011, 2012 OpenSSL Software Foundation, Inc.
>   + *
> @@ -8932,7 +10613,7 @@ index 0000000..884dbab
>   +	return 0;
>   +}
>   +
> -+int adjust_sg_array(struct csession * ses, int pagecount)
> ++int adjust_sg_array(struct csession *ses, int pagecount)
>   +{
>   +	struct scatterlist *sg;
>   +	struct page **pages;
> @@ -8941,7 +10622,7 @@ index 0000000..884dbab
>   +	for (array_size = ses->array_size; array_size < pagecount;
>   +	     array_size *= 2)
>   +		;
> -+	dprintk(0, KERN_DEBUG, "reallocating from %d to %d pages\n",
> ++	ddebug(0, "reallocating from %d to %d pages",
>   +			ses->array_size, array_size);
>   +	pages = krealloc(ses->pages, array_size * sizeof(struct page *),
>   +			 GFP_KERNEL);
> @@ -8962,7 +10643,7 @@ index 0000000..884dbab
>   +{
>   +	unsigned int i;
>   +
> -+	for (i=0;i<ses->used_pages;i++) {
> ++	for (i = 0; i < ses->used_pages; i++) {
>   +		if (!PageReserved(ses->pages[i]))
>   +			SetPageDirty(ses->pages[i]);
>   +
> @@ -8980,8 +10661,8 @@ index 0000000..884dbab
>   + * dst might be the same as src.
>   + */
>   +int get_userbuf(struct csession *ses,
> -+                void* __user src, unsigned int src_len,
> -+                void* __user dst, unsigned int dst_len,
> ++                void *__user src, unsigned int src_len,
> ++                void *__user dst, unsigned int dst_len,
>   +                struct task_struct *task, struct mm_struct *mm,
>   +                struct scatterlist **src_sg,
>   +                struct scatterlist **dst_sg)
> @@ -8999,16 +10680,6 @@ index 0000000..884dbab
>   +	if (!dst && dst_len)
>   +		dst_len = 0;
>   +
> -+	if (ses->alignmask && !IS_ALIGNED((unsigned long)src, ses->alignmask)) {
> -+		dprintk(2, KERN_WARNING, "careful - source address %lx is not %d byte aligned\n",
> -+				(unsigned long)src, ses->alignmask + 1);
> -+	}
> -+
> -+	if (ses->alignmask && !IS_ALIGNED((unsigned long)dst, ses->alignmask)) {
> -+		dprintk(2, KERN_WARNING, "careful - destination address %lx is not %d byte aligned\n",
> -+				(unsigned long)dst, ses->alignmask + 1);
> -+	}
> -+
>   +	src_pagecount = PAGECOUNT(src, src_len);
>   +	dst_pagecount = PAGECOUNT(dst, dst_len);
>   +
> @@ -9024,32 +10695,34 @@ index 0000000..884dbab
>   +	}
>   +
>   +	if (src == dst) {	/* inplace operation */
> ++		/* When we encrypt for authenc modes we need to write
> ++		 * more data than the ones we read. */
> ++		if (src_len < dst_len)
> ++			src_len = dst_len;
>   +		rc = __get_userbuf(src, src_len, 1, ses->used_pages,
>   +			               ses->pages, ses->sg, task, mm);
>   +		if (unlikely(rc)) {
> -+			dprintk(1, KERN_ERR,
> -+				"failed to get user pages for data IO\n");
> ++			derr(1, "failed to get user pages for data IO");
>   +			return rc;
>   +		}
>   +		(*src_sg) = (*dst_sg) = ses->sg;
>   +		return 0;
>   +	}
>   +
> -+	*src_sg = NULL; // default to no input
> -+	*dst_sg = NULL; // default to ignore output
> ++	*src_sg = NULL; /* default to no input */
> ++	*dst_sg = NULL; /* default to ignore output */
>   +
> -+	if(likely(src)) {
> ++	if (likely(src)) {
>   +		rc = __get_userbuf(src, src_len, 0, ses->readonly_pages,
>   +					   ses->pages, ses->sg, task, mm);
>   +		if (unlikely(rc)) {
> -+			dprintk(1, KERN_ERR,
> -+				"failed to get user pages for data input\n");
> ++			derr(1, "failed to get user pages for data input");
>   +			return rc;
>   +		}
>   +		*src_sg = ses->sg;
>   +	}
>   +
> -+	if(likely(dst)) {
> ++	if (likely(dst)) {
>   +		const unsigned int writable_pages =
>   +			ses->used_pages - ses->readonly_pages;
>   +		struct page **dst_pages = ses->pages + ses->readonly_pages;
> @@ -9058,8 +10731,7 @@ index 0000000..884dbab
>   +		rc = __get_userbuf(dst, dst_len, 1, writable_pages,
>   +					   dst_pages, *dst_sg, task, mm);
>   +		if (unlikely(rc)) {
> -+			dprintk(1, KERN_ERR,
> -+					"failed to get user pages for data output\n");
> ++			derr(1, "failed to get user pages for data output");
>   +			release_user_pages(ses);  /* FIXME: use __release_userbuf(src, ...) */
>   +			return rc;
>   +		}
> @@ -9069,7 +10741,7 @@ index 0000000..884dbab
>   +
>   diff --git a/crypto/cryptodev/zc.h b/crypto/cryptodev/zc.h
>   new file mode 100644
> -index 0000000..b52616e
> +index 0000000..6f975d6
>   --- /dev/null
>   +++ b/crypto/cryptodev/zc.h
>   @@ -0,0 +1,27 @@
> @@ -9082,11 +10754,11 @@ index 0000000..b52616e
>   +int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
>   +		unsigned int pgcount, struct page **pg, struct scatterlist *sg,
>   +		struct task_struct *task, struct mm_struct *mm);
> -+void release_user_pages(struct csession* ses);
> ++void release_user_pages(struct csession *ses);
>   +
>   +int get_userbuf(struct csession *ses,
> -+                void* __user src, unsigned int src_len,
> -+                void* __user dst, unsigned int dst_len,
> ++                void *__user src, unsigned int src_len,
> ++                void *__user dst, unsigned int dst_len,
>   +                struct task_struct *task, struct mm_struct *mm,
>   +                struct scatterlist **src_sg,
>   +                struct scatterlist **dst_sg);
> @@ -9101,5 +10773,5 @@ index 0000000..b52616e
>   +
>   +#endif
>   --
> -1.7.10.4
> +1.9.1
>
>



More information about the linux-yocto mailing list