From 4a4f0eb8ce4c981222955b8d4c9f4c7b8deb03aa Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <nmav@gnutls.org>
Date: Sat, 28 Nov 2009 19:35:35 +0200
Subject: [PATCH 004/291] cryptodev: Added

---
 drivers/staging/crypto/cryptodev/cryptodev.c     | 184 ++++++++++++++---------
 drivers/staging/crypto/cryptodev/cryptodev.h     |  29 +++-
 drivers/staging/crypto/cryptodev/cryptodev.mod.c |  57 -------
 3 files changed, 139 insertions(+), 131 deletions(-)
 delete mode 100644 drivers/staging/crypto/cryptodev/cryptodev.mod.c

diff --git a/drivers/staging/crypto/cryptodev/cryptodev.c b/drivers/staging/crypto/cryptodev/cryptodev.c
index 60076484e8e3..76581c46f79a 100644
--- a/drivers/staging/crypto/cryptodev/cryptodev.c
+++ b/drivers/staging/crypto/cryptodev/cryptodev.c
@@ -401,10 +401,7 @@ crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
 	return ses_ptr;
 }
 
-/* This is the main crypto function - feed it with plaintext 
-   and get a ciphertext (or vice versa :-) */
-static int
-crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
+static int crypto_runv(struct fcrypt *fcr, struct crypt_opv *copv)
 {
 	char *data, ivp[EALG_MAX_BLOCK_LEN];
 	char __user *src, __user *dst;
@@ -414,6 +411,7 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
 	size_t nbytes, bufsize;
 	int ret = 0;
 	uint8_t hash_output[HASH_MAX_LEN];
+	int blocksize=1, i;
 	struct blkcipher_desc bdesc = {
         .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
 	};
@@ -422,29 +420,27 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
 	};
 
 
-	if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
-		dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
+	if (unlikely(copv->op != COP_ENCRYPT && copv->op != COP_DECRYPT)) {
+		dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", copv->op);
 		return -EINVAL;
 	}
 
-	ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
+	ses_ptr = crypto_get_session_by_sid(fcr, copv->ses);
 	if (!ses_ptr) {
-		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
+		dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", copv->ses);
 		return -EINVAL;
 	}
 
-	nbytes = cop->len;
 	data = (char*)__get_free_page(GFP_KERNEL);
 
 	if (unlikely(!data)) {
 		ret = -ENOMEM;
 		goto out_unlock;
 	}
-	bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
 
-	nbytes = cop->len;
 	bdesc.tfm = ses_ptr->tfm;
 	hdesc.tfm = ses_ptr->hash_tfm;
+
 	if (hdesc.tfm) {
 		ret = crypto_hash_init(&hdesc);
 		if (unlikely(ret)) {
@@ -455,7 +451,21 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
 	}
 
 	if (ses_ptr->tfm) {
-		if (nbytes % crypto_blkcipher_blocksize(ses_ptr->tfm)) {
+		blocksize = crypto_blkcipher_blocksize(ses_ptr->tfm);
+		ivsize = crypto_blkcipher_ivsize(ses_ptr->tfm);
+
+		if (copv->iv) {
+			copy_from_user(ivp, copv->iv, ivsize);
+			crypto_blkcipher_set_iv(ses_ptr->tfm, ivp, ivsize);
+		}
+	}
+
+	dst = copv->dst;
+
+	for (i=0;i<copv->iovec_cnt;i++) {
+		nbytes = copv->iovec[i].len;
+
+		if (unlikely(bdesc.tfm && (nbytes % blocksize))) {
 			dprintk(1, KERN_ERR,
 				"data size (%zu) isn't a multiple of block size (%u)\n",
 				nbytes, crypto_blkcipher_blocksize(ses_ptr->tfm));
@@ -463,70 +473,74 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
 			goto out_unlock;
 		}
 
-		ivsize = crypto_blkcipher_ivsize(ses_ptr->tfm);
-
-		if (cop->iv) {
-			copy_from_user(ivp, cop->iv, ivsize);
-			crypto_blkcipher_set_iv(ses_ptr->tfm, ivp, ivsize);
-		}
-	}
-
-	src = cop->src;
-	dst = cop->dst;
+		bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
 
+		src = copv->iovec[i].src;
 
-	while(nbytes > 0) {
-		size_t current_len = nbytes > bufsize ? bufsize : nbytes;
+		while(nbytes > 0) {
+			size_t current_len = nbytes > bufsize ? bufsize : nbytes;
 
-		copy_from_user(data, src, current_len);
+			copy_from_user(data, src, current_len);
 
-		sg_set_buf(&sg, data, current_len);
+			sg_set_buf(&sg, data, current_len);
 
-		/* Always hash before encryption and after decryption. Maybe
-		 * we should introduce a flag to switch... TBD later on.
-		 */
-		if (cop->op == COP_ENCRYPT) {
-			if (hdesc.tfm) {
-				ret = crypto_hash_update(&hdesc, &sg, current_len);
-				if (unlikely(ret)) {
-					dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
-					goto out;
+			/* Always hash before encryption and after decryption. Maybe
+			 * we should introduce a flag to switch... TBD later on.
+			 */
+			if (copv->op == COP_ENCRYPT) {
+				if (hdesc.tfm && (copv->iovec[i].op_flags & IOP_HASH)) {
+					ret = crypto_hash_update(&hdesc, &sg, current_len);
+					if (unlikely(ret)) {
+						dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
+						goto out;
+					}
 				}
-			}
-			if (bdesc.tfm) {
-				ret = crypto_blkcipher_encrypt(&bdesc, &sg, &sg, current_len);
-
-				if (unlikely(ret)) {
-					dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
-					goto out;
+				if (bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER)) {
+					ret = crypto_blkcipher_encrypt(&bdesc, &sg, &sg, current_len);
+
+					if (unlikely(ret)) {
+						dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
+						goto out;
+					}
+					copy_to_user(dst, data, current_len);
+					dst += current_len;
 				}
-				copy_to_user(dst, data, current_len);
-				dst += current_len;
-			}
-		} else {
-			if (bdesc.tfm) {
-				ret = crypto_blkcipher_decrypt(&bdesc, &sg, &sg, current_len);
+			} else {
+				if (bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER)) {
+					ret = crypto_blkcipher_decrypt(&bdesc, &sg, &sg, current_len);
 
-				if (unlikely(ret)) {
-					dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
-					goto out;
-				}
-				copy_to_user(dst, data, current_len);
-				dst += current_len;
+					if (unlikely(ret)) {
+						dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
+						goto out;
+					}
+					copy_to_user(dst, data, current_len);
+					dst += current_len;
 
-			}
+				}
 
-			if (hdesc.tfm) {
-				ret = crypto_hash_update(&hdesc, &sg, current_len);
-				if (unlikely(ret)) {
-					dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
-					goto out;
+				if (hdesc.tfm && (copv->iovec[i].op_flags & IOP_HASH)) {
+					ret = crypto_hash_update(&hdesc, &sg, current_len);
+					if (unlikely(ret)) {
+						dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
+						goto out;
+					}
 				}
 			}
+
+			nbytes -= current_len;
+			src += current_len;
 		}
 
-		nbytes -= current_len;
-		src += current_len;
+#if defined(CRYPTODEV_STATS)
+	if (enable_stats) {
+		/* this is safe - we check cop->op at the function entry */
+		ses_ptr->stat[copv->op] += copv->iovec[i].len;
+		if (ses_ptr->stat_max_size < copv->iovec[i].len)
+			ses_ptr->stat_max_size = copv->iovec[i].len;
+		ses_ptr->stat_count++;
+	}
+#endif
+
 	}
 	
 	if (hdesc.tfm) {
@@ -536,19 +550,9 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
 			goto out;
 		}
 
-		copy_to_user(cop->mac, hash_output, crypto_hash_digestsize(ses_ptr->hash_tfm));
+		copy_to_user(copv->mac, hash_output, crypto_hash_digestsize(ses_ptr->hash_tfm));
 	}
 
-#if defined(CRYPTODEV_STATS)
-	if (enable_stats) {
-		/* this is safe - we check cop->op at the function entry */
-		ses_ptr->stat[cop->op] += cop->len;
-		if (ses_ptr->stat_max_size < cop->len)
-			ses_ptr->stat_max_size = cop->len;
-		ses_ptr->stat_count++;
-	}
-#endif
-
 out:
 	free_page((unsigned long)data);
 
@@ -558,6 +562,33 @@ out_unlock:
 	return ret;
 }
 
+/* This is the main crypto function - feed it with plaintext 
+   and get a ciphertext (or vice versa :-) */
+static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
+{
+	struct crypt_opv copv;
+	struct crypt_iovec iovec;
+	
+	iovec.src = cop->src;
+	iovec.len = cop->len;
+	iovec.op_flags = IOP_CIPHER|IOP_HASH;
+	
+	copv.op = cop->op;
+	copv.ses = cop->ses;
+	copv.flags = cop->flags;
+	copv.iovec = &iovec;
+	copv.iovec_cnt = 1;
+
+	copv.dst = cop->dst;
+	copv.mac = cop->mac;
+	copv.iv = cop->iv;
+	
+	return crypto_runv(fcr, &copv);
+	
+}
+
+
+
 /* ====== /dev/crypto ====== */
 
 static int
@@ -613,6 +644,7 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
 	int __user *p = (void __user *)arg;
 	struct session_op sop;
 	struct crypt_op cop;
+	struct crypt_opv copv;
 	struct fcrypt *fcr = filp->private_data;
 	uint32_t ses;
 	int ret, fd;
@@ -648,6 +680,12 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
 			copy_to_user((void*)arg, &cop, sizeof(cop));
 			return ret;
 
+		case CIOCCRYPTV:
+			copy_from_user(&cop, (void*)arg, sizeof(copv));
+			ret = crypto_runv(fcr, &copv);
+			copy_to_user((void*)arg, &copv, sizeof(copv));
+			return ret;
+
 		default:
 			return -EINVAL;
 	}
diff --git a/drivers/staging/crypto/cryptodev/cryptodev.h b/drivers/staging/crypto/cryptodev/cryptodev.h
index 895ad1cad4e3..891ad2ac7dd2 100644
--- a/drivers/staging/crypto/cryptodev/cryptodev.h
+++ b/drivers/staging/crypto/cryptodev/cryptodev.h
@@ -75,7 +75,7 @@ struct crypt_op {
 	uint32_t	ses;		/* from session_op->ses */
 	#define COP_DECRYPT	0
 	#define COP_ENCRYPT	1
-	uint32_t	op;		/* ie. COP_ENCRYPT */
+	uint16_t	op;		/* ie. COP_ENCRYPT */
 	uint32_t	flags;		/* unused */
 
 	size_t		len;
@@ -84,6 +84,30 @@ struct crypt_op {
 	void		*iv;
 };
 
+struct crypt_iovec {
+#define IOP_CIPHER 1
+#define IOP_HASH 2
+	uint16_t	op_flags;		/* ie. IOP_CIPHER|IOP_HASH */
+	void		*src;
+	size_t		len;
+};
+
+/* ioctl parameter to request a crypt/decrypt operation against a session  */
+struct crypt_opv {
+	uint32_t	ses;		/* from session_op->ses */
+	#define COP_DECRYPT	0
+	#define COP_ENCRYPT	1
+	uint16_t	op;		/* ie. COP_ENCRYPT */
+	uint32_t	flags;		/* unused */
+
+	struct crypt_iovec* iovec;
+	uint16_t iovec_cnt;
+	
+	void		*dst;
+	void		*mac;
+	void		*iv;
+};
+
 /* clone original filedescriptor */
 #define CRIOGET         _IOWR('c', 101, uint32_t)
 
@@ -100,6 +124,9 @@ struct crypt_op {
 #define CIOCKEY         _IOWR('c', 105, void *)
 #define CIOCASYMFEAT    _IOR('c', 106, uint32_t)
 
+/* request encryption/decryptions of a given buffer vector */
+#define CIOCCRYPTV       _IOWR('c', 107, struct crypt_opv)
+
 #endif /* _CRYPTODEV_H */
 
 /* unused structures */
diff --git a/drivers/staging/crypto/cryptodev/cryptodev.mod.c b/drivers/staging/crypto/cryptodev/cryptodev.mod.c
deleted file mode 100644
index 983f1f47903d..000000000000
--- a/drivers/staging/crypto/cryptodev/cryptodev.mod.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <linux/module.h>
-#include <linux/vermagic.h>
-#include <linux/compiler.h>
-
-MODULE_INFO(vermagic, VERMAGIC_STRING);
-
-struct module __this_module
-__attribute__((section(".gnu.linkonce.this_module"))) = {
- .name = KBUILD_MODNAME,
- .init = init_module,
-#ifdef CONFIG_MODULE_UNLOAD
- .exit = cleanup_module,
-#endif
- .arch = MODULE_ARCH_INIT,
-};
-
-static const struct modversion_info ____versions[]
-__used
-__attribute__((section("__versions"))) = {
-	{ 0x903a5ec4, "module_layout" },
-	{ 0x6980fe91, "param_get_int" },
-	{ 0xff964b25, "param_set_int" },
-	{ 0x79aa04a2, "get_random_bytes" },
-	{ 0x4661e311, "__tracepoint_kmalloc" },
-	{ 0x893412fe, "kmem_cache_alloc" },
-	{ 0xadee93f3, "kmalloc_caches" },
-	{ 0x4e1e7401, "crypto_alloc_base" },
-	{ 0x4302d0eb, "free_pages" },
-	{ 0xe52947e7, "__phys_addr" },
-	{ 0x236c8c64, "memcpy" },
-	{ 0xbe499d81, "copy_to_user" },
-	{ 0x93fca811, "__get_free_pages" },
-	{ 0x37a0cba, "kfree" },
-	{ 0x3f1899f1, "up" },
-	{ 0x9bf377f5, "crypto_destroy_tfm" },
-	{ 0x9ced38aa, "down_trylock" },
-	{ 0x945bc6a7, "copy_from_user" },
-	{ 0x748caf40, "down" },
-	{ 0x6729d3df, "__get_user_4" },
-	{ 0xf0fdf6cb, "__stack_chk_fail" },
-	{ 0xb2fd5ceb, "__put_user_4" },
-	{ 0xa1c76e0a, "_cond_resched" },
-	{ 0xa62a61be, "fd_install" },
-	{ 0x99bfbe39, "get_unused_fd" },
-	{ 0xd8778690, "per_cpu__current_task" },
-	{ 0x54b8041c, "misc_register" },
-	{ 0xea147363, "printk" },
-	{ 0x11cef3ea, "misc_deregister" },
-};
-
-static const char __module_depends[]
-__used
-__attribute__((section(".modinfo"))) =
-"depends=";
-
-
-MODULE_INFO(srcversion, "A0688FBD1488A8A38E2DF83");
-- 
2.1.0

