[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