From 7ac54939d406ae16a35614e7ee3fd6a485ebe8b7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil.sutter@viprinet.com>
Date: Tue, 15 Jun 2010 18:17:50 +0200
Subject: [PATCH 042/291] cryptodev: add

---
 drivers/staging/crypto/cryptodev/cryptodev.h      | 38 +++++++++
 drivers/staging/crypto/cryptodev/cryptodev_main.c | 93 +++++++++++++++++++++++
 2 files changed, 131 insertions(+)

diff --git a/drivers/staging/crypto/cryptodev/cryptodev.h b/drivers/staging/crypto/cryptodev/cryptodev.h
index 84d371b24cbc..fc9414905d28 100644
--- a/drivers/staging/crypto/cryptodev/cryptodev.h
+++ b/drivers/staging/crypto/cryptodev/cryptodev.h
@@ -150,4 +150,42 @@ typedef enum {
 #define CIOCKEY         _IOWR('c', 105, struct crypt_kop)
 #define CIOCASYMFEAT    _IOR('c', 106, uint32_t)
 
+/* compatibility code for 32bit userlands */
+
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+
+/* input of CIOCGSESSION */
+struct compat_session_op {
+	/* Specify either cipher or mac
+	 */
+	uint32_t	cipher;		/* cryptodev_crypto_op_t */
+	uint32_t	mac;		/* cryptodev_crypto_op_t */
+
+	uint32_t	keylen;
+	uint32_t	key;		/* pointer to key data */
+	uint32_t	mackeylen;
+	uint32_t	mackey;		/* pointer to mac key data */
+
+	uint32_t	ses;		/* session identifier */
+};
+
+/* input of CIOCCRYPT */
+ struct compat_crypt_op {
+	uint32_t	ses;		/* session identifier */
+	uint16_t	op;		/* COP_ENCRYPT or COP_DECRYPT */
+	uint16_t	flags;		/* no usage so far, use 0 */
+	uint32_t	len;		/* length of source data */
+	uint32_t	src;		/* source data */
+	uint32_t	dst;		/* pointer to output data */
+	uint32_t	mac;		/* pointer to output data for hash/MAC operations */
+	uint32_t	iv;		/* initialization vector for encryption operations */
+};
+
+#define COMPAT_CIOCGSESSION    _IOWR('c', 102, struct compat_session_op)
+#define COMPAT_CIOCCRYPT       _IOWR('c', 104, struct compat_crypt_op)
+
+#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
+
 #endif /* L_CRYPTODEV_H */
diff --git a/drivers/staging/crypto/cryptodev/cryptodev_main.c b/drivers/staging/crypto/cryptodev/cryptodev_main.c
index 4146a3c7b076..f5a2635e3dd4 100644
--- a/drivers/staging/crypto/cryptodev/cryptodev_main.c
+++ b/drivers/staging/crypto/cryptodev/cryptodev_main.c
@@ -582,11 +582,104 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
 	}
 }
 
+static inline void
+compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
+{
+	memcpy(sop, compat, sizeof(uint32_t) * 3);
+	sop->key       = (uint8_t *)compat->key;
+	sop->mackeylen = compat->mackeylen;
+	sop->mackey    = (uint8_t *)compat->mackey;
+	sop->ses       = compat->ses;
+}
+
+static inline void
+session_op_to_compat(struct session_op *sop, struct compat_session_op *compat)
+{
+	memcpy(compat, sop, sizeof(uint32_t) * 3);
+	compat->key       = (uint32_t)sop->key;
+	compat->mackeylen = sop->mackeylen;
+	compat->mackey    = (uint32_t)sop->mackey;
+	compat->ses       = sop->ses;
+}
+
+static inline void
+compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop)
+{
+	memcpy(cop, compat, sizeof(uint32_t) * 2 + sizeof(uint16_t) * 2);
+	cop->src = (uint8_t *)compat->src;
+	cop->dst = (uint8_t *)compat->dst;
+	cop->mac = (uint8_t *)compat->mac;
+	cop->iv  = (uint8_t *)compat->iv;
+}
+
+static inline void
+crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat)
+{
+	memcpy(compat, cop, sizeof(uint32_t) * 2 + sizeof(uint16_t) * 2);
+	compat->src = (uint32_t)cop->src;
+	compat->dst = (uint32_t)cop->dst;
+	compat->mac = (uint32_t)cop->mac;
+	compat->iv  = (uint32_t)cop->iv;
+}
+
+static long
+cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct fcrypt *fcr = file->private_data;
+	struct session_op sop;
+	struct compat_session_op compat_sop;
+	struct crypt_op cop;
+	struct compat_crypt_op compat_cop;
+	int ret;
+
+	if (unlikely(!fcr))
+		BUG();
+
+	switch (cmd) {
+	case CIOCASYMFEAT:
+	case CRIOGET:
+	case CIOCFSESSION:
+		return cryptodev_ioctl(NULL, file, cmd, arg);
+
+	case COMPAT_CIOCGSESSION:
+		copy_from_user(&compat_sop, (void *)arg,
+				sizeof(compat_sop));
+		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);
+		copy_to_user((void*)arg, &compat_sop,
+				sizeof(compat_sop));
+		return 0;
+
+	case COMPAT_CIOCCRYPT:
+		copy_from_user(&compat_cop, (void*)arg,
+				sizeof(compat_cop));
+		compat_to_crypto_op(&compat_op, &cop);
+
+		ret = crypto_run(fcr, &cop);
+		if (unlikely(ret))
+			return ret;
+
+		crypto_op_to_compat(&cop, &compat_op);
+		copy_to_user((void*)arg, &compat_cop,
+				sizeof(compat_cop));
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 struct file_operations cryptodev_fops = {
 	.owner = THIS_MODULE,
 	.open = cryptodev_open,
 	.release = cryptodev_release,
 	.ioctl = cryptodev_ioctl,
+	.compat_ioctl = cryptodev_compat_ioctl,
 };
 
 struct miscdevice cryptodev = {
-- 
2.1.0

