From 20dcf071bc3076ee7db9d603cfbe6a06e86c7d5f Mon Sep 17 00:00:00 2001
From: Cristian Stoica <cristian.stoica@nxp.com>
Date: Thu, 4 May 2017 15:06:20 +0300
Subject: [PATCH 1/3] refactoring: split big function to simplify maintainance

The setup of auth_buf in tls and aead is now duplicated but this
is temporary and allows necessary corrections for the aead case
with v4.2+ kernels.

Signed-off-by: Cristian Stoica <cristian.stoica@nxp.com>

Upstream-Status: Backport

Commit ID: 20dcf071bc3076ee7db9d603c

Signed-off-by: Hongzhi.Song <hongzhi.song@windriver.com>
---
 authenc.c | 197 ++++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 126 insertions(+), 71 deletions(-)

diff --git a/authenc.c b/authenc.c
index 1bd7377..28eb0f9 100644
--- a/authenc.c
+++ b/authenc.c
@@ -609,96 +609,151 @@ auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop,
 	return 0;
 }
 
-/* This is the main crypto function - zero-copy edition */
-static int
-__crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop)
+static int crypto_auth_zc_srtp(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop)
 {
-	struct scatterlist *dst_sg, *auth_sg, *src_sg;
+	struct scatterlist *dst_sg, *auth_sg;
 	struct crypt_auth_op *caop = &kcaop->caop;
-	int ret = 0;
+	int ret;
 
-	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))) {
-			derr(0, "Only stream modes are allowed in SRTP mode (but not AEAD)");
-			return -EINVAL;
-		}
+	if (unlikely(ses_ptr->cdata.init != 0 &&
+		(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)) {
-			derr(1, "get_userbuf_srtp(): Error getting user pages.");
-			return ret;
-		}
+	ret = get_userbuf_srtp(ses_ptr, kcaop, &auth_sg, &dst_sg);
+	if (unlikely(ret)) {
+		derr(1, "get_userbuf_srtp(): Error getting user pages.");
+		return ret;
+	}
 
-		ret = srtp_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
-			   dst_sg, caop->len);
+	ret = srtp_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
+			dst_sg, caop->len);
 
-		release_user_pages(ses_ptr);
-	} else { /* TLS and normal cases. Here auth data are usually small
-	          * so we just copy them to a free page, instead of trying
-	          * to map them.
-	          */
-		unsigned char *auth_buf = NULL;
-		struct scatterlist tmp;
+	release_user_pages(ses_ptr);
 
-		if (unlikely(caop->auth_len > PAGE_SIZE)) {
-			derr(1, "auth data len is excessive.");
-			return -EINVAL;
-		}
+	return ret;
+}
 
-		auth_buf = (char *)__get_free_page(GFP_KERNEL);
-		if (unlikely(!auth_buf)) {
-			derr(1, "unable to get a free page.");
-			return -ENOMEM;
-		}
+static int crypto_auth_zc_tls(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop)
+{
+	struct crypt_auth_op *caop = &kcaop->caop;
+	struct scatterlist *dst_sg, *auth_sg;
+	unsigned char *auth_buf = NULL;
+	struct scatterlist tmp;
+	int ret;
 
-		if (caop->auth_src && caop->auth_len > 0) {
-			if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) {
-				derr(1, "unable to copy auth data from userspace.");
-				ret = -EFAULT;
-				goto free_auth_buf;
-			}
+	if (unlikely(ses_ptr->cdata.aead != 0)) {
+		return -EINVAL;
+	}
+
+	if (unlikely(caop->auth_len > PAGE_SIZE)) {
+		derr(1, "auth data len is excessive.");
+		return -EINVAL;
+	}
+
+	auth_buf = (char *)__get_free_page(GFP_KERNEL);
+	if (unlikely(!auth_buf)) {
+		derr(1, "unable to get a free page.");
+		return -ENOMEM;
+	}
 
-			sg_init_one(&tmp, auth_buf, caop->auth_len);
-			auth_sg = &tmp;
-		} else {
-			auth_sg = NULL;
+	if (caop->auth_src && caop->auth_len > 0) {
+		if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) {
+			derr(1, "unable to copy auth data from userspace.");
+			ret = -EFAULT;
+			goto free_auth_buf;
 		}
 
-		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)) {
-				derr(1, "get_userbuf_tls(): Error getting user pages.");
-				goto free_auth_buf;
-			}
+		sg_init_one(&tmp, auth_buf, caop->auth_len);
+		auth_sg = &tmp;
+	} else {
+		auth_sg = NULL;
+	}
 
-			ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
-				   dst_sg, caop->len);
-		} else {
-			if (unlikely(ses_ptr->cdata.init == 0 ||
-			             (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;
-			}
+	ret = get_userbuf_tls(ses_ptr, kcaop, &dst_sg);
+	if (unlikely(ret)) {
+		derr(1, "get_userbuf_tls(): Error getting user pages.");
+		goto free_auth_buf;
+	}
 
-			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)) {
-				derr(1, "get_userbuf(): 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);
+	release_user_pages(ses_ptr);
+
+free_auth_buf:
+	free_page((unsigned long)auth_buf);
+	return ret;
+}
+
+static int crypto_auth_zc_aead(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop)
+{
+	struct scatterlist *dst_sg, *auth_sg, *src_sg;
+	struct crypt_auth_op *caop = &kcaop->caop;
+	unsigned char *auth_buf = NULL;
+	struct scatterlist tmp;
+	int ret;
 
-			ret = auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
-					   src_sg, dst_sg, caop->len);
+	if (unlikely(ses_ptr->cdata.init == 0 ||
+		(ses_ptr->cdata.stream == 0 && ses_ptr->cdata.aead == 0))) {
+		derr(0, "Only stream and AEAD ciphers are allowed for authenc");
+		return -EINVAL;
+	}
+
+	if (unlikely(caop->auth_len > PAGE_SIZE)) {
+		derr(1, "auth data len is excessive.");
+		return -EINVAL;
+	}
+
+	auth_buf = (char *)__get_free_page(GFP_KERNEL);
+	if (unlikely(!auth_buf)) {
+		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))) {
+			derr(1, "unable to copy auth data from userspace.");
+			ret = -EFAULT;
+			goto free_auth_buf;
 		}
 
-		release_user_pages(ses_ptr);
+		sg_init_one(&tmp, auth_buf, caop->auth_len);
+		auth_sg = &tmp;
+	} else {
+		auth_sg = NULL;
+	}
+
+	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)) {
+		derr(1, "get_userbuf(): Error getting user pages.");
+		goto free_auth_buf;
+	}
+
+	ret = auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
+			src_sg, dst_sg, caop->len);
+
+	release_user_pages(ses_ptr);
 
 free_auth_buf:
-		free_page((unsigned long)auth_buf);
+	free_page((unsigned long)auth_buf);
+
+	return ret;
+}
+
+static int
+__crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop)
+{
+	struct crypt_auth_op *caop = &kcaop->caop;
+	int ret;
+
+	if (caop->flags & COP_FLAG_AEAD_SRTP_TYPE) {
+		ret = crypto_auth_zc_srtp(ses_ptr, kcaop);
+	} else if (caop->flags & COP_FLAG_AEAD_TLS_TYPE) {
+		ret = crypto_auth_zc_tls(ses_ptr, kcaop);
+	} else {
+		ret = crypto_auth_zc_aead(ses_ptr, kcaop);
 	}
 
 	return ret;
-- 
2.11.0

