/*
* algif_aead: User-space interface for AEAD algorithms
*
* Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
*
* This file provides the user-space API for AEAD ciphers.
*
* 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.
*
* The following concept of the memory management is used:
*
* The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is
* filled by user space with the data submitted via sendpage/sendmsg. Filling
* up the TX SGL does not cause a crypto operation -- the data will only be
* tracked by the kernel. Upon receipt of one recvmsg call, the caller must
* provide a buffer which is tracked with the RX SGL.
*
* During the processing of the recvmsg operation, the cipher request is
* allocated and prepared. As part of the recvmsg operation, the processed
* TX buffers are extracted from the TX SGL into a separate SGL.
*
* After the completion of the crypto operation, the RX SGL and the cipher
* request is released. The extracted TX SGL parts are released together with
* the RX SGL release.
*/
#include <crypto/internal/aead.h>
#include <crypto/scatterwalk.h>
#include <crypto/if_alg.h>
#include <crypto/skcipher.h>
#include <crypto/null.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/net.h>
#include <net/sock.h>
struct aead_tsgl {
struct list_head list;
unsigned int cur; /* Last processed SG entry */
struct scatterlist sg[0]; /* Array of SGs forming the SGL */
};
struct aead_rsgl {
struct af_alg_sgl sgl;
struct list_head list;
size_t sg_num_bytes; /* Bytes of data in that SGL */
};
struct aead_async_req {
struct kiocb *iocb;
struct sock *sk;
struct aead_rsgl first_rsgl; /* First RX SG */
struct list_head rsgl_list; /* Track RX SGs */
struct scatterlist *tsgl; /* priv. TX SGL of buffers to process */
unsigned int tsgl_entries; /* number of entries in priv. TX SGL */
unsigned int outlen; /* Filled output buf length */
unsigned int areqlen; /* Length of this data struct */
struct aead_request aead_req; /* req ctx trails this struct */
};
struct aead_tfm {
struct crypto_aead *aead;
bool has_key;
struct crypto_skcipher *null_tfm;
};
struct aead_ctx {
struct list_head tsgl_list; /* Link to TX SGL */
void *iv;
size_t aead_assoclen;
struct af_alg_completion completion; /* sync work queue */
size_t used; /* TX bytes sent to kernel */
size_t rcvused; /* total RX bytes to be processed by kernel */
bool more; /* More data to be expected? */
bool merge; /* Merge new data into existing SG */
bool enc; /* Crypto operation: enc, dec */
unsigned int len; /* Length of allocated memory for this struct */
};
#define MAX_SGL_ENTS ((4096 - sizeof(struct aead_tsgl)) / \
sizeof(struct scatterlist) - 1)
static inline int aead_sndbuf(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) -
ctx->used, 0);
}
static inline bool aead_writable(struct sock *sk)
{
return PAGE_SIZE <= aead_sndbuf(sk);
}
static inline int aead_rcvbuf(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
return max_t(int, max_t(int<