18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * algif_rng: User-space interface for random number generators
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file provides the user-space API for random number generators.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
108c2ecf20Sopenharmony_ci * are met:
118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
128c2ecf20Sopenharmony_ci *    notice, and the entire permission notice in its entirety,
138c2ecf20Sopenharmony_ci *    including the disclaimer of warranties.
148c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
158c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
168c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
178c2ecf20Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote
188c2ecf20Sopenharmony_ci *    products derived from this software without specific prior
198c2ecf20Sopenharmony_ci *    written permission.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * ALTERNATIVELY, this product may be distributed under the terms of
228c2ecf20Sopenharmony_ci * the GNU General Public License, in which case the provisions of the GPL2
238c2ecf20Sopenharmony_ci * are required INSTEAD OF the above restrictions.  (This clause is
248c2ecf20Sopenharmony_ci * necessary due to a potential bad interaction between the GPL and
258c2ecf20Sopenharmony_ci * the restrictions contained in a BSD-style copyright.)
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
288c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
298c2ecf20Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
308c2ecf20Sopenharmony_ci * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
318c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
328c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
338c2ecf20Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
348c2ecf20Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
358c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
368c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
378c2ecf20Sopenharmony_ci * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
388c2ecf20Sopenharmony_ci * DAMAGE.
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <linux/capability.h>
428c2ecf20Sopenharmony_ci#include <linux/module.h>
438c2ecf20Sopenharmony_ci#include <crypto/rng.h>
448c2ecf20Sopenharmony_ci#include <linux/random.h>
458c2ecf20Sopenharmony_ci#include <crypto/if_alg.h>
468c2ecf20Sopenharmony_ci#include <linux/net.h>
478c2ecf20Sopenharmony_ci#include <net/sock.h>
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("User-space interface for random number generators");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistruct rng_ctx {
548c2ecf20Sopenharmony_ci#define MAXSIZE 128
558c2ecf20Sopenharmony_ci	unsigned int len;
568c2ecf20Sopenharmony_ci	struct crypto_rng *drng;
578c2ecf20Sopenharmony_ci	u8 *addtl;
588c2ecf20Sopenharmony_ci	size_t addtl_len;
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct rng_parent_ctx {
628c2ecf20Sopenharmony_ci	struct crypto_rng *drng;
638c2ecf20Sopenharmony_ci	u8 *entropy;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void rng_reset_addtl(struct rng_ctx *ctx)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	kfree_sensitive(ctx->addtl);
698c2ecf20Sopenharmony_ci	ctx->addtl = NULL;
708c2ecf20Sopenharmony_ci	ctx->addtl_len = 0;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len,
748c2ecf20Sopenharmony_ci			u8 *addtl, size_t addtl_len)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int err = 0;
778c2ecf20Sopenharmony_ci	int genlen = 0;
788c2ecf20Sopenharmony_ci	u8 result[MAXSIZE];
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (len == 0)
818c2ecf20Sopenharmony_ci		return 0;
828c2ecf20Sopenharmony_ci	if (len > MAXSIZE)
838c2ecf20Sopenharmony_ci		len = MAXSIZE;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/*
868c2ecf20Sopenharmony_ci	 * although not strictly needed, this is a precaution against coding
878c2ecf20Sopenharmony_ci	 * errors
888c2ecf20Sopenharmony_ci	 */
898c2ecf20Sopenharmony_ci	memset(result, 0, len);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/*
928c2ecf20Sopenharmony_ci	 * The enforcement of a proper seeding of an RNG is done within an
938c2ecf20Sopenharmony_ci	 * RNG implementation. Some RNGs (DRBG, krng) do not need specific
948c2ecf20Sopenharmony_ci	 * seeding as they automatically seed. The X9.31 DRNG will return
958c2ecf20Sopenharmony_ci	 * an error if it was not seeded properly.
968c2ecf20Sopenharmony_ci	 */
978c2ecf20Sopenharmony_ci	genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len);
988c2ecf20Sopenharmony_ci	if (genlen < 0)
998c2ecf20Sopenharmony_ci		return genlen;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	err = memcpy_to_msg(msg, result, len);
1028c2ecf20Sopenharmony_ci	memzero_explicit(result, len);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return err ? err : len;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
1088c2ecf20Sopenharmony_ci		       int flags)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
1118c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
1128c2ecf20Sopenharmony_ci	struct rng_ctx *ctx = ask->private;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return _rng_recvmsg(ctx->drng, msg, len, NULL, 0);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
1188c2ecf20Sopenharmony_ci			    int flags)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
1218c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
1228c2ecf20Sopenharmony_ci	struct rng_ctx *ctx = ask->private;
1238c2ecf20Sopenharmony_ci	int ret;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	lock_sock(sock->sk);
1268c2ecf20Sopenharmony_ci	ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len);
1278c2ecf20Sopenharmony_ci	rng_reset_addtl(ctx);
1288c2ecf20Sopenharmony_ci	release_sock(sock->sk);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return ret;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	int err;
1368c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sock->sk);
1378c2ecf20Sopenharmony_ci	struct rng_ctx *ctx = ask->private;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	lock_sock(sock->sk);
1408c2ecf20Sopenharmony_ci	if (len > MAXSIZE) {
1418c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
1428c2ecf20Sopenharmony_ci		goto unlock;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	rng_reset_addtl(ctx);
1468c2ecf20Sopenharmony_ci	ctx->addtl = kmalloc(len, GFP_KERNEL);
1478c2ecf20Sopenharmony_ci	if (!ctx->addtl) {
1488c2ecf20Sopenharmony_ci		err = -ENOMEM;
1498c2ecf20Sopenharmony_ci		goto unlock;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	err = memcpy_from_msg(ctx->addtl, msg, len);
1538c2ecf20Sopenharmony_ci	if (err) {
1548c2ecf20Sopenharmony_ci		rng_reset_addtl(ctx);
1558c2ecf20Sopenharmony_ci		goto unlock;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci	ctx->addtl_len = len;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ciunlock:
1608c2ecf20Sopenharmony_ci	release_sock(sock->sk);
1618c2ecf20Sopenharmony_ci	return err ? err : len;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic struct proto_ops algif_rng_ops = {
1658c2ecf20Sopenharmony_ci	.family		=	PF_ALG,
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	.connect	=	sock_no_connect,
1688c2ecf20Sopenharmony_ci	.socketpair	=	sock_no_socketpair,
1698c2ecf20Sopenharmony_ci	.getname	=	sock_no_getname,
1708c2ecf20Sopenharmony_ci	.ioctl		=	sock_no_ioctl,
1718c2ecf20Sopenharmony_ci	.listen		=	sock_no_listen,
1728c2ecf20Sopenharmony_ci	.shutdown	=	sock_no_shutdown,
1738c2ecf20Sopenharmony_ci	.mmap		=	sock_no_mmap,
1748c2ecf20Sopenharmony_ci	.bind		=	sock_no_bind,
1758c2ecf20Sopenharmony_ci	.accept		=	sock_no_accept,
1768c2ecf20Sopenharmony_ci	.sendmsg	=	sock_no_sendmsg,
1778c2ecf20Sopenharmony_ci	.sendpage	=	sock_no_sendpage,
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	.release	=	af_alg_release,
1808c2ecf20Sopenharmony_ci	.recvmsg	=	rng_recvmsg,
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic struct proto_ops __maybe_unused algif_rng_test_ops = {
1848c2ecf20Sopenharmony_ci	.family		=	PF_ALG,
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	.connect	=	sock_no_connect,
1878c2ecf20Sopenharmony_ci	.socketpair	=	sock_no_socketpair,
1888c2ecf20Sopenharmony_ci	.getname	=	sock_no_getname,
1898c2ecf20Sopenharmony_ci	.ioctl		=	sock_no_ioctl,
1908c2ecf20Sopenharmony_ci	.listen		=	sock_no_listen,
1918c2ecf20Sopenharmony_ci	.shutdown	=	sock_no_shutdown,
1928c2ecf20Sopenharmony_ci	.mmap		=	sock_no_mmap,
1938c2ecf20Sopenharmony_ci	.bind		=	sock_no_bind,
1948c2ecf20Sopenharmony_ci	.accept		=	sock_no_accept,
1958c2ecf20Sopenharmony_ci	.sendpage	=	sock_no_sendpage,
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	.release	=	af_alg_release,
1988c2ecf20Sopenharmony_ci	.recvmsg	=	rng_test_recvmsg,
1998c2ecf20Sopenharmony_ci	.sendmsg	=	rng_test_sendmsg,
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic void *rng_bind(const char *name, u32 type, u32 mask)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct rng_parent_ctx *pctx;
2058c2ecf20Sopenharmony_ci	struct crypto_rng *rng;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
2088c2ecf20Sopenharmony_ci	if (!pctx)
2098c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	rng = crypto_alloc_rng(name, type, mask);
2128c2ecf20Sopenharmony_ci	if (IS_ERR(rng)) {
2138c2ecf20Sopenharmony_ci		kfree(pctx);
2148c2ecf20Sopenharmony_ci		return ERR_CAST(rng);
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	pctx->drng = rng;
2188c2ecf20Sopenharmony_ci	return pctx;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic void rng_release(void *private)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct rng_parent_ctx *pctx = private;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (unlikely(!pctx))
2268c2ecf20Sopenharmony_ci		return;
2278c2ecf20Sopenharmony_ci	crypto_free_rng(pctx->drng);
2288c2ecf20Sopenharmony_ci	kfree_sensitive(pctx->entropy);
2298c2ecf20Sopenharmony_ci	kfree_sensitive(pctx);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void rng_sock_destruct(struct sock *sk)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
2358c2ecf20Sopenharmony_ci	struct rng_ctx *ctx = ask->private;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	rng_reset_addtl(ctx);
2388c2ecf20Sopenharmony_ci	sock_kfree_s(sk, ctx, ctx->len);
2398c2ecf20Sopenharmony_ci	af_alg_release_parent(sk);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int rng_accept_parent(void *private, struct sock *sk)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct rng_ctx *ctx;
2458c2ecf20Sopenharmony_ci	struct rng_parent_ctx *pctx = private;
2468c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
2478c2ecf20Sopenharmony_ci	unsigned int len = sizeof(*ctx);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
2508c2ecf20Sopenharmony_ci	if (!ctx)
2518c2ecf20Sopenharmony_ci		return -ENOMEM;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	ctx->len = len;
2548c2ecf20Sopenharmony_ci	ctx->addtl = NULL;
2558c2ecf20Sopenharmony_ci	ctx->addtl_len = 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	 * No seeding done at that point -- if multiple accepts are
2598c2ecf20Sopenharmony_ci	 * done on one RNG instance, each resulting FD points to the same
2608c2ecf20Sopenharmony_ci	 * state of the RNG.
2618c2ecf20Sopenharmony_ci	 */
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	ctx->drng = pctx->drng;
2648c2ecf20Sopenharmony_ci	ask->private = ctx;
2658c2ecf20Sopenharmony_ci	sk->sk_destruct = rng_sock_destruct;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/*
2688c2ecf20Sopenharmony_ci	 * Non NULL pctx->entropy means that CAVP test has been initiated on
2698c2ecf20Sopenharmony_ci	 * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops.
2708c2ecf20Sopenharmony_ci	 */
2718c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy)
2728c2ecf20Sopenharmony_ci		sk->sk_socket->ops = &algif_rng_test_ops;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return 0;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct rng_parent_ctx *pctx = private;
2808c2ecf20Sopenharmony_ci	/*
2818c2ecf20Sopenharmony_ci	 * Check whether seedlen is of sufficient size is done in RNG
2828c2ecf20Sopenharmony_ci	 * implementations.
2838c2ecf20Sopenharmony_ci	 */
2848c2ecf20Sopenharmony_ci	return crypto_rng_reset(pctx->drng, seed, seedlen);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int __maybe_unused rng_setentropy(void *private, sockptr_t entropy,
2888c2ecf20Sopenharmony_ci					 unsigned int len)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct rng_parent_ctx *pctx = private;
2918c2ecf20Sopenharmony_ci	u8 *kentropy = NULL;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
2948c2ecf20Sopenharmony_ci		return -EACCES;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (pctx->entropy)
2978c2ecf20Sopenharmony_ci		return -EINVAL;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (len > MAXSIZE)
3008c2ecf20Sopenharmony_ci		return -EMSGSIZE;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (len) {
3038c2ecf20Sopenharmony_ci		kentropy = memdup_sockptr(entropy, len);
3048c2ecf20Sopenharmony_ci		if (IS_ERR(kentropy))
3058c2ecf20Sopenharmony_ci			return PTR_ERR(kentropy);
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);
3098c2ecf20Sopenharmony_ci	/*
3108c2ecf20Sopenharmony_ci	 * Since rng doesn't perform any memory management for the entropy
3118c2ecf20Sopenharmony_ci	 * buffer, save kentropy pointer to pctx now to free it after use.
3128c2ecf20Sopenharmony_ci	 */
3138c2ecf20Sopenharmony_ci	pctx->entropy = kentropy;
3148c2ecf20Sopenharmony_ci	return 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic const struct af_alg_type algif_type_rng = {
3188c2ecf20Sopenharmony_ci	.bind		=	rng_bind,
3198c2ecf20Sopenharmony_ci	.release	=	rng_release,
3208c2ecf20Sopenharmony_ci	.accept		=	rng_accept_parent,
3218c2ecf20Sopenharmony_ci	.setkey		=	rng_setkey,
3228c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP
3238c2ecf20Sopenharmony_ci	.setentropy	=	rng_setentropy,
3248c2ecf20Sopenharmony_ci#endif
3258c2ecf20Sopenharmony_ci	.ops		=	&algif_rng_ops,
3268c2ecf20Sopenharmony_ci	.name		=	"rng",
3278c2ecf20Sopenharmony_ci	.owner		=	THIS_MODULE
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int __init rng_init(void)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	return af_alg_register_type(&algif_type_rng);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void __exit rng_exit(void)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int err = af_alg_unregister_type(&algif_type_rng);
3388c2ecf20Sopenharmony_ci	BUG_ON(err);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cimodule_init(rng_init);
3428c2ecf20Sopenharmony_cimodule_exit(rng_exit);
343