|  | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 
|  | /* | 
|  | * if_alg: User-space algorithm interface | 
|  | * | 
|  | * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> | 
|  | */ | 
|  |  | 
|  | #ifndef _CRYPTO_IF_ALG_H | 
|  | #define _CRYPTO_IF_ALG_H | 
|  |  | 
|  | #include <linux/compiler.h> | 
|  | #include <linux/completion.h> | 
|  | #include <linux/if_alg.h> | 
|  | #include <linux/scatterlist.h> | 
|  | #include <linux/types.h> | 
|  | #include <linux/atomic.h> | 
|  | #include <net/sock.h> | 
|  |  | 
|  | #include <crypto/aead.h> | 
|  | #include <crypto/skcipher.h> | 
|  |  | 
|  | #define ALG_MAX_PAGES			16 | 
|  |  | 
|  | struct crypto_async_request; | 
|  |  | 
|  | struct alg_sock { | 
|  | /* struct sock must be the first member of struct alg_sock */ | 
|  | struct sock sk; | 
|  |  | 
|  | struct sock *parent; | 
|  |  | 
|  | atomic_t refcnt; | 
|  | atomic_t nokey_refcnt; | 
|  |  | 
|  | const struct af_alg_type *type; | 
|  | void *private; | 
|  | }; | 
|  |  | 
|  | struct af_alg_control { | 
|  | struct af_alg_iv *iv; | 
|  | int op; | 
|  | unsigned int aead_assoclen; | 
|  | }; | 
|  |  | 
|  | struct af_alg_type { | 
|  | void *(*bind)(const char *name, u32 type, u32 mask); | 
|  | void (*release)(void *private); | 
|  | int (*setkey)(void *private, const u8 *key, unsigned int keylen); | 
|  | int (*setentropy)(void *private, sockptr_t entropy, unsigned int len); | 
|  | int (*accept)(void *private, struct sock *sk); | 
|  | int (*accept_nokey)(void *private, struct sock *sk); | 
|  | int (*setauthsize)(void *private, unsigned int authsize); | 
|  |  | 
|  | struct proto_ops *ops; | 
|  | struct proto_ops *ops_nokey; | 
|  | struct module *owner; | 
|  | char name[14]; | 
|  | }; | 
|  |  | 
|  | struct af_alg_sgl { | 
|  | struct scatterlist sg[ALG_MAX_PAGES + 1]; | 
|  | struct page *pages[ALG_MAX_PAGES]; | 
|  | unsigned int npages; | 
|  | }; | 
|  |  | 
|  | /* TX SGL entry */ | 
|  | struct af_alg_tsgl { | 
|  | struct list_head list; | 
|  | unsigned int cur;		/* Last processed SG entry */ | 
|  | struct scatterlist sg[];	/* Array of SGs forming the SGL */ | 
|  | }; | 
|  |  | 
|  | #define MAX_SGL_ENTS ((4096 - sizeof(struct af_alg_tsgl)) / \ | 
|  | sizeof(struct scatterlist) - 1) | 
|  |  | 
|  | /* RX SGL entry */ | 
|  | struct af_alg_rsgl { | 
|  | struct af_alg_sgl sgl; | 
|  | struct list_head list; | 
|  | size_t sg_num_bytes;		/* Bytes of data in that SGL */ | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * struct af_alg_async_req - definition of crypto request | 
|  | * @iocb:		IOCB for AIO operations | 
|  | * @sk:			Socket the request is associated with | 
|  | * @first_rsgl:		First RX SG | 
|  | * @last_rsgl:		Pointer to last RX SG | 
|  | * @rsgl_list:		Track RX SGs | 
|  | * @tsgl:		Private, per request TX SGL of buffers to process | 
|  | * @tsgl_entries:	Number of entries in priv. TX SGL | 
|  | * @outlen:		Number of output bytes generated by crypto op | 
|  | * @areqlen:		Length of this data structure | 
|  | * @cra_u:		Cipher request | 
|  | */ | 
|  | struct af_alg_async_req { | 
|  | struct kiocb *iocb; | 
|  | struct sock *sk; | 
|  |  | 
|  | struct af_alg_rsgl first_rsgl; | 
|  | struct af_alg_rsgl *last_rsgl; | 
|  | struct list_head rsgl_list; | 
|  |  | 
|  | struct scatterlist *tsgl; | 
|  | unsigned int tsgl_entries; | 
|  |  | 
|  | unsigned int outlen; | 
|  | unsigned int areqlen; | 
|  |  | 
|  | union { | 
|  | struct aead_request aead_req; | 
|  | struct skcipher_request skcipher_req; | 
|  | } cra_u; | 
|  |  | 
|  | /* req ctx trails this struct */ | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * struct af_alg_ctx - definition of the crypto context | 
|  | * | 
|  | * The crypto context tracks the input data during the lifetime of an AF_ALG | 
|  | * socket. | 
|  | * | 
|  | * @tsgl_list:		Link to TX SGL | 
|  | * @iv:			IV for cipher operation | 
|  | * @aead_assoclen:	Length of AAD for AEAD cipher operations | 
|  | * @completion:		Work queue for synchronous operation | 
|  | * @used:		TX bytes sent to kernel. This variable is used to | 
|  | *			ensure that user space cannot cause the kernel | 
|  | *			to allocate too much memory in sendmsg operation. | 
|  | * @rcvused:		Total RX bytes to be filled by kernel. This variable | 
|  | *			is used to ensure user space cannot cause the kernel | 
|  | *			to allocate too much memory in a recvmsg operation. | 
|  | * @more:		More data to be expected from user space? | 
|  | * @merge:		Shall new data from user space be merged into existing | 
|  | *			SG? | 
|  | * @enc:		Cryptographic operation to be performed when | 
|  | *			recvmsg is invoked. | 
|  | * @init:		True if metadata has been sent. | 
|  | * @len:		Length of memory allocated for this data structure. | 
|  | * @inflight:		Non-zero when AIO requests are in flight. | 
|  | */ | 
|  | struct af_alg_ctx { | 
|  | struct list_head tsgl_list; | 
|  |  | 
|  | void *iv; | 
|  | size_t aead_assoclen; | 
|  |  | 
|  | struct crypto_wait wait; | 
|  |  | 
|  | size_t used; | 
|  | atomic_t rcvused; | 
|  |  | 
|  | bool more; | 
|  | bool merge; | 
|  | bool enc; | 
|  | bool init; | 
|  |  | 
|  | unsigned int len; | 
|  |  | 
|  | unsigned int inflight; | 
|  | }; | 
|  |  | 
|  | int af_alg_register_type(const struct af_alg_type *type); | 
|  | int af_alg_unregister_type(const struct af_alg_type *type); | 
|  |  | 
|  | int af_alg_release(struct socket *sock); | 
|  | void af_alg_release_parent(struct sock *sk); | 
|  | int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern); | 
|  |  | 
|  | int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len); | 
|  | void af_alg_free_sg(struct af_alg_sgl *sgl); | 
|  |  | 
|  | static inline struct alg_sock *alg_sk(struct sock *sk) | 
|  | { | 
|  | return (struct alg_sock *)sk; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Size of available buffer for sending data from user space to kernel. | 
|  | * | 
|  | * @sk socket of connection to user space | 
|  | * @return number of bytes still available | 
|  | */ | 
|  | static inline int af_alg_sndbuf(struct sock *sk) | 
|  | { | 
|  | struct alg_sock *ask = alg_sk(sk); | 
|  | struct af_alg_ctx *ctx = ask->private; | 
|  |  | 
|  | return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) - | 
|  | ctx->used, 0); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Can the send buffer still be written to? | 
|  | * | 
|  | * @sk socket of connection to user space | 
|  | * @return true => writable, false => not writable | 
|  | */ | 
|  | static inline bool af_alg_writable(struct sock *sk) | 
|  | { | 
|  | return PAGE_SIZE <= af_alg_sndbuf(sk); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Size of available buffer used by kernel for the RX user space operation. | 
|  | * | 
|  | * @sk socket of connection to user space | 
|  | * @return number of bytes still available | 
|  | */ | 
|  | static inline int af_alg_rcvbuf(struct sock *sk) | 
|  | { | 
|  | struct alg_sock *ask = alg_sk(sk); | 
|  | struct af_alg_ctx *ctx = ask->private; | 
|  |  | 
|  | return max_t(int, max_t(int, sk->sk_rcvbuf & PAGE_MASK, PAGE_SIZE) - | 
|  | atomic_read(&ctx->rcvused), 0); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Can the RX buffer still be written to? | 
|  | * | 
|  | * @sk socket of connection to user space | 
|  | * @return true => writable, false => not writable | 
|  | */ | 
|  | static inline bool af_alg_readable(struct sock *sk) | 
|  | { | 
|  | return PAGE_SIZE <= af_alg_rcvbuf(sk); | 
|  | } | 
|  |  | 
|  | unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); | 
|  | void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, | 
|  | size_t dst_offset); | 
|  | void af_alg_wmem_wakeup(struct sock *sk); | 
|  | int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); | 
|  | int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, | 
|  | unsigned int ivsize); | 
|  | ssize_t af_alg_sendpage(struct socket *sock, struct page *page, | 
|  | int offset, size_t size, int flags); | 
|  | void af_alg_free_resources(struct af_alg_async_req *areq); | 
|  | void af_alg_async_cb(struct crypto_async_request *_req, int err); | 
|  | __poll_t af_alg_poll(struct file *file, struct socket *sock, | 
|  | poll_table *wait); | 
|  | struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, | 
|  | unsigned int areqlen); | 
|  | int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, | 
|  | struct af_alg_async_req *areq, size_t maxsize, | 
|  | size_t *outlen); | 
|  |  | 
|  | #endif	/* _CRYPTO_IF_ALG_H */ |