On 14 April 2017 at 00:04, Abed Kamaluddin <abed...@gmail.com> wrote:
> crypto: algif_compression - User-space interface for compression
>
> This patch adds af_alg plugin for compression algorithms of type scomp/acomp
> registered to the kernel crypto layer.
>
> The user needs to set operation (compression/decompression) as a control
> message to sendmsg, identical to selecting the cipher operation type in case 
> of
> ciphers. Once a sendmsg call occurs, no further writes can be made to the
> socket until all previous data has been processed and read. Therefore the
> interface only supports one request at a time.
>
> The interface is completely synchronous; all operations are carried out in
> recvmsg and will complete prior to the system call returning.
>
> The sendmsg and recvmsg interface supports directly reading/writing to
> user-space without additional copying, i.e., the kernel crypto interface will
> receive the user-space address as its input/output SG list. The scomp 
> interface
> or crypto drivers may copy the data as required.
>
> Signed-off-by: Abed Kamaluddin <akam...@cavium.com>
> Signed-off-by: Mahipal Challa <mahipal.cha...@cavium.com>
>
> ---
>  crypto/Kconfig              |  11 ++
>  crypto/Makefile             |   1 +
>  crypto/algif_compression.c  | 272 
> ++++++++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/if_alg.h |   2 +
>  4 files changed, 286 insertions(+)
>
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index f37e9cc..13b03ba 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -1741,6 +1741,17 @@ config CRYPTO_USER_API_AEAD
>           This option enables the user-spaces interface for AEAD
>           cipher algorithms.
>
> +config CRYPTO_USER_API_COMPRESSION
> +       tristate "User-space interface for compression algorithms"
> +       depends on NET
> +       select CRYPTO_ACOMP
> +       select CRYPTO_USER_API
> +       help
> +         This option enables the user-space interface for compression
> +         algorithms. Enable this option for access to compression algorithms
> +         of type scomp/acomp exported by the kernel crypto layer through
> +         AF_ALG interface.
> +
>  config CRYPTO_HASH_INFO
>         bool
>
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 8a44057..1469e06 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -134,6 +134,7 @@ obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
>  obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
>  obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
>  obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
> +obj-$(CONFIG_CRYPTO_USER_API_COMPRESSION) += algif_compression.o
>  obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
>  obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
>  obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
> diff --git a/crypto/algif_compression.c b/crypto/algif_compression.c
> new file mode 100644
> index 0000000..0ba6d1e
> --- /dev/null
> +++ b/crypto/algif_compression.c
> @@ -0,0 +1,272 @@
> +/*
> + * algif_compression: User-space interface for COMPRESSION algorithms
> + *
> + * This file provides user-space API support for compression algorithms
> + * registered through the kernel crypto layer.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + *
> + * Original Authors: Abed Kamaluddin <akamalud...@cavium.com>
> + *
> + * 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.
> + */
> +
> +#include <crypto/acompress.h>
> +#include <crypto/if_alg.h>
> +#include <linux/crypto.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/net.h>
> +#include <net/sock.h>
> +#include <linux/scatterlist.h>
> +
> +/* scomp scratch is currently 128KB */
> +#define COMP_BUFFER_SIZE       65535
> +
> +struct comp_ctx {
> +       struct af_alg_sgl tsgl;
> +       struct af_alg_sgl rsgl;
> +       struct af_alg_completion completion;
> +       unsigned int clen;
> +       unsigned int slen;
> +       unsigned int dlen;
> +       bool comp;
> +       bool used;
> +       struct acomp_req *acomp_req;
> +};

Is it necessary to have 3 len fields viz clen, slen, dlen? Please add
a comment indicating their purpose.

> +struct comp_tfm {
> +       struct crypto_acomp *acomp;
> +};
> +
> +static int comp_sendmsg(struct socket *sock, struct msghdr *msg,
> +                       size_t ignored)
> +{
> +       struct sock *sk = sock->sk;
> +       struct alg_sock *ask = alg_sk(sk);
> +       struct comp_ctx *ctx = ask->private;
> +       struct af_alg_control con = {};
> +       int limit = COMP_BUFFER_SIZE;
> +       int len;
> +       int err = -EINVAL;
> +
> +       if (msg->msg_controllen) {
> +               err = af_alg_cmsg_send(msg, &con);
> +               if (err)
> +                       return err;
> +
> +               switch (con.op) {
> +               case ALG_OP_COMPRESS:
> +                       ctx->comp = 1;
> +                       break;
> +
> +               case ALG_OP_DECOMPRESS:
> +                       ctx->comp = 0;
> +                       break;
> +
> +               default:
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       lock_sock(sk);
> +
> +       /* One request at a time supported, data submitted for comp/decomp 
> will
> +        * be processed at subsequent recvmsg
> +        */
> +       if (ctx->used) {
> +               err = -EAGAIN;
> +               goto unlock;
> +       }
> +
> +       len = msg_data_left(msg);
> +
> +       if (len > limit)
> +               len = limit;
> +
> +       len = af_alg_make_sg(&ctx->tsgl, &msg->msg_iter, len);
> +
> +       if (len < 0) {
> +               err = len;
> +               goto unlock;
> +       }
> +
> +       ctx->slen = len;
> +       ctx->used = 1;
> +
> +unlock:
> +       release_sock(sk);
> +
> +       return err ?: len;
> +}
> +
> +static int comp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
> +                       int flags)
> +{
> +       struct sock *sk = sock->sk;
> +       struct alg_sock *ask = alg_sk(sk);
> +       struct comp_ctx *ctx = ask->private;
> +       int rlen = ctx->dlen;
> +       int err;
> +
> +       if (len > rlen)
> +               len = rlen;
> +
> +       lock_sock(sk);
> +
> +       if (!ctx->used) {
> +               err = -EAGAIN;
> +               goto unlock;
> +       }
> +
> +       len = af_alg_make_sg(&ctx->rsgl, &msg->msg_iter, len);
> +       if (len < 0) {
> +               err = len;
> +               goto unlock;
> +       }
> +
> +       acomp_request_set_params(ctx->acomp_req, ctx->tsgl.sg, ctx->rsgl.sg,
> +                                ctx->slen, len);
> +
> +       /* Synchronous completion of comp/decomp requests */
> +       err = af_alg_wait_for_completion(
> +                       ctx->comp ?
> +                               crypto_acomp_compress(ctx->acomp_req) :
> +                               crypto_acomp_decompress(ctx->acomp_req),
> +                               &ctx->completion);
> +
> +       /* Add acomp req wrapper for dlen */
> +       len = (ctx->acomp_req)->dlen;
> +
> +       af_alg_free_sg(&ctx->tsgl);
> +       af_alg_free_sg(&ctx->rsgl);
> +
> +unlock:
> +       ctx->used = 0;
> +       release_sock(sk);
> +
> +       return err ?: len;
> +}
> +
> +static struct proto_ops algif_comp_ops = {
> +       .family         =       PF_ALG,
> +
> +       .connect        =       sock_no_connect,
> +       .socketpair     =       sock_no_socketpair,
> +       .getname        =       sock_no_getname,
> +       .ioctl          =       sock_no_ioctl,
> +       .listen         =       sock_no_listen,
> +       .shutdown       =       sock_no_shutdown,
> +       .getsockopt     =       sock_no_getsockopt,
> +       .mmap           =       sock_no_mmap,
> +       .bind           =       sock_no_bind,
> +       .setsockopt     =       sock_no_setsockopt,
> +       .poll           =       sock_no_poll,
> +
> +       .release        =       af_alg_release,
> +       .sendmsg        =       comp_sendmsg,
> +       .recvmsg        =       comp_recvmsg,
> +       .sendpage       =       sock_no_sendpage,
> +       .accept         =       sock_no_accept,
> +};
> +
> +static void *comp_bind(const char *name, u32 type, u32 mask)
> +{
> +       struct comp_tfm *tfm;
> +       struct crypto_acomp *acomp;
> +
> +       tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
> +       if (!tfm)
> +               return ERR_PTR(-ENOMEM);
> +
> +       acomp = crypto_alloc_acomp(name, type, mask);
> +       if (IS_ERR_OR_NULL(acomp)) {
> +               kfree(tfm);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +       tfm->acomp = acomp;
> +
> +       return tfm;
> +}
> +
> +static void comp_release(void *private)
> +{
> +       struct comp_tfm *tfm = private;
> +
> +       crypto_free_acomp(tfm->acomp);
> +       kfree(tfm);
> +}
> +
> +static void comp_sock_destruct(struct sock *sk)
> +{
> +       struct alg_sock *ask = alg_sk(sk);
> +       struct comp_ctx *ctx = ask->private;
> +
> +       acomp_request_free(ctx->acomp_req);
> +       sock_kfree_s(sk, ctx, ctx->clen);
> +       af_alg_release_parent(sk);
> +}
> +
> +static int comp_accept_parent(void *private, struct sock *sk)
> +{
> +       struct comp_ctx *ctx;
> +       struct alg_sock *ask = alg_sk(sk);
> +       struct comp_tfm *tfm = private;
> +       struct crypto_acomp *acomp = tfm->acomp;
> +       unsigned int len = sizeof(*ctx);
> +
> +       ctx = sock_kmalloc(sk, len, GFP_KERNEL);
> +       if (!ctx)
> +               return -ENOMEM;
> +
> +       ctx->used = 0;
> +       ctx->clen = len;
> +       ctx->dlen = COMP_BUFFER_SIZE;
> +       ctx->slen = COMP_BUFFER_SIZE;
> +
> +       af_alg_init_completion(&ctx->completion);
> +
> +       ctx->acomp_req = acomp_request_alloc(acomp);
> +       if (!ctx->acomp_req) {
> +               sock_kfree_s(sk, ctx, ctx->clen);
> +               return -ENOMEM;
> +       }
> +
> +       acomp_request_set_callback(ctx->acomp_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +                                  af_alg_complete, &ctx->completion);
> +
> +       ask->private = ctx;
> +       sk->sk_destruct = comp_sock_destruct;
> +
> +       return 0;
> +}
> +
> +static const struct af_alg_type algif_type_comp = {
> +       .bind           =       comp_bind,
> +       .release        =       comp_release,
> +       .accept         =       comp_accept_parent,
> +       .ops            =       &algif_comp_ops,
> +       .name           =       "compression",
> +       .owner          =       THIS_MODULE
> +};
> +
> +static int __init algif_comp_init(void)
> +{
> +       return af_alg_register_type(&algif_type_comp);
> +}
> +
> +static void __exit algif_comp_exit(void)
> +{
> +       int err = af_alg_unregister_type(&algif_type_comp);
> +
> +       BUG_ON(err);
> +}
> +
> +module_init(algif_comp_init);
> +module_exit(algif_comp_exit);
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
> index f2acd2f..5cca9eb 100644
> --- a/include/uapi/linux/if_alg.h
> +++ b/include/uapi/linux/if_alg.h
> @@ -38,5 +38,7 @@ struct af_alg_iv {
>  /* Operations */
>  #define ALG_OP_DECRYPT                 0
>  #define ALG_OP_ENCRYPT                 1
> +#define ALG_OP_DECOMPRESS              0
> +#define ALG_OP_COMPRESS                1
>
>  #endif /* _LINUX_IF_ALG_H */
> --
> 2.7.4
>

Regards,
PrasannaKumar

Reply via email to