As it stands algif_skcipher assumes all algorithms support chaining.
This patch teaches it about the new fcsize attribute which can be
used to disable chaining on a given algorithm.  It can also be used
to support chaining on algorithms such as cts that cannot otherwise
do chaining.  For that case algif_skcipher will also now set the
request flag CRYPTO_TFM_REQ_MORE when needed.

Signed-off-by: Herbert Xu <herb...@gondor.apana.org.au>
---

 crypto/algif_skcipher.c |   30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index f8a7fca3203eb..7fc873d28f4a7 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -57,12 +57,18 @@ static int _skcipher_recvmsg(struct socket *sock, struct 
msghdr *msg,
        struct af_alg_ctx *ctx = ask->private;
        struct crypto_skcipher *tfm = pask->private;
        unsigned int bs = crypto_skcipher_chunksize(tfm);
+       unsigned int rflags = CRYPTO_TFM_REQ_MAY_SLEEP;
+       int fc = crypto_skcipher_fcsize(tfm);
        struct af_alg_async_req *areq;
+       unsigned int min = bs;
        int err = 0;
        size_t len = 0;
 
-       if (!ctx->init || (ctx->more && ctx->used < bs)) {
-               err = af_alg_wait_for_data(sk, flags, bs);
+       if (fc >= 0)
+               min += fc;
+
+       if (!ctx->init || (ctx->more && ctx->used < min)) {
+               err = af_alg_wait_for_data(sk, flags, min);
                if (err)
                        return err;
        }
@@ -78,13 +84,22 @@ static int _skcipher_recvmsg(struct socket *sock, struct 
msghdr *msg,
        if (err)
                goto free;
 
+       err = -EINVAL;
+
        /*
         * If more buffers are to be expected to be processed, process only
-        * full block size buffers.
+        * full block size buffers and withhold data according to fcsize.
         */
-       if (ctx->more || len < ctx->used)
+       if (ctx->more || len < ctx->used) {
+               if (fc < 0)
+                       goto free;
+
+               len -= fc;
                len -= len % bs;
 
+               rflags |= CRYPTO_TFM_REQ_MORE;
+       }
+
        /*
         * Create a per request TX SGL for this request which tracks the
         * SG entries from the global TX SGL.
@@ -116,8 +131,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct 
msghdr *msg,
                areq->outlen = len;
 
                skcipher_request_set_callback(&areq->cra_u.skcipher_req,
-                                             CRYPTO_TFM_REQ_MAY_SLEEP,
-                                             af_alg_async_cb, areq);
+                                             rflags, af_alg_async_cb, areq);
                err = ctx->enc ?
                        crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
                        crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
@@ -129,9 +143,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct 
msghdr *msg,
                sock_put(sk);
        } else {
                /* Synchronous operation */
+               rflags |= CRYPTO_TFM_REQ_MAY_BACKLOG;
                skcipher_request_set_callback(&areq->cra_u.skcipher_req,
-                                             CRYPTO_TFM_REQ_MAY_SLEEP |
-                                             CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                             rflags,
                                              crypto_req_done, &ctx->wait);
                err = crypto_wait_req(ctx->enc ?
                        crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :

Reply via email to