xref: /linux/crypto/af_alg.c (revision c840ac6af3f8713a71b4d2363419145760bd6044)
103c8efc1SHerbert Xu /*
203c8efc1SHerbert Xu  * af_alg: User-space algorithm interface
303c8efc1SHerbert Xu  *
403c8efc1SHerbert Xu  * This file provides the user-space API for algorithms.
503c8efc1SHerbert Xu  *
603c8efc1SHerbert Xu  * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
703c8efc1SHerbert Xu  *
803c8efc1SHerbert Xu  * This program is free software; you can redistribute it and/or modify it
903c8efc1SHerbert Xu  * under the terms of the GNU General Public License as published by the Free
1003c8efc1SHerbert Xu  * Software Foundation; either version 2 of the License, or (at your option)
1103c8efc1SHerbert Xu  * any later version.
1203c8efc1SHerbert Xu  *
1303c8efc1SHerbert Xu  */
1403c8efc1SHerbert Xu 
1560063497SArun Sharma #include <linux/atomic.h>
1603c8efc1SHerbert Xu #include <crypto/if_alg.h>
1703c8efc1SHerbert Xu #include <linux/crypto.h>
1803c8efc1SHerbert Xu #include <linux/init.h>
1903c8efc1SHerbert Xu #include <linux/kernel.h>
2003c8efc1SHerbert Xu #include <linux/list.h>
2103c8efc1SHerbert Xu #include <linux/module.h>
2203c8efc1SHerbert Xu #include <linux/net.h>
2303c8efc1SHerbert Xu #include <linux/rwsem.h>
244c63f83cSMilan Broz #include <linux/security.h>
2503c8efc1SHerbert Xu 
2603c8efc1SHerbert Xu struct alg_type_list {
2703c8efc1SHerbert Xu 	const struct af_alg_type *type;
2803c8efc1SHerbert Xu 	struct list_head list;
2903c8efc1SHerbert Xu };
3003c8efc1SHerbert Xu 
3106869524SRandy Dunlap static atomic_long_t alg_memory_allocated;
3203c8efc1SHerbert Xu 
3303c8efc1SHerbert Xu static struct proto alg_proto = {
3403c8efc1SHerbert Xu 	.name			= "ALG",
3503c8efc1SHerbert Xu 	.owner			= THIS_MODULE,
3603c8efc1SHerbert Xu 	.memory_allocated	= &alg_memory_allocated,
3703c8efc1SHerbert Xu 	.obj_size		= sizeof(struct alg_sock),
3803c8efc1SHerbert Xu };
3903c8efc1SHerbert Xu 
4003c8efc1SHerbert Xu static LIST_HEAD(alg_types);
4103c8efc1SHerbert Xu static DECLARE_RWSEM(alg_types_sem);
4203c8efc1SHerbert Xu 
4303c8efc1SHerbert Xu static const struct af_alg_type *alg_get_type(const char *name)
4403c8efc1SHerbert Xu {
4503c8efc1SHerbert Xu 	const struct af_alg_type *type = ERR_PTR(-ENOENT);
4603c8efc1SHerbert Xu 	struct alg_type_list *node;
4703c8efc1SHerbert Xu 
4803c8efc1SHerbert Xu 	down_read(&alg_types_sem);
4903c8efc1SHerbert Xu 	list_for_each_entry(node, &alg_types, list) {
5003c8efc1SHerbert Xu 		if (strcmp(node->type->name, name))
5103c8efc1SHerbert Xu 			continue;
5203c8efc1SHerbert Xu 
5303c8efc1SHerbert Xu 		if (try_module_get(node->type->owner))
5403c8efc1SHerbert Xu 			type = node->type;
5503c8efc1SHerbert Xu 		break;
5603c8efc1SHerbert Xu 	}
5703c8efc1SHerbert Xu 	up_read(&alg_types_sem);
5803c8efc1SHerbert Xu 
5903c8efc1SHerbert Xu 	return type;
6003c8efc1SHerbert Xu }
6103c8efc1SHerbert Xu 
6203c8efc1SHerbert Xu int af_alg_register_type(const struct af_alg_type *type)
6303c8efc1SHerbert Xu {
6403c8efc1SHerbert Xu 	struct alg_type_list *node;
6503c8efc1SHerbert Xu 	int err = -EEXIST;
6603c8efc1SHerbert Xu 
6703c8efc1SHerbert Xu 	down_write(&alg_types_sem);
6803c8efc1SHerbert Xu 	list_for_each_entry(node, &alg_types, list) {
6903c8efc1SHerbert Xu 		if (!strcmp(node->type->name, type->name))
7003c8efc1SHerbert Xu 			goto unlock;
7103c8efc1SHerbert Xu 	}
7203c8efc1SHerbert Xu 
7303c8efc1SHerbert Xu 	node = kmalloc(sizeof(*node), GFP_KERNEL);
7403c8efc1SHerbert Xu 	err = -ENOMEM;
7503c8efc1SHerbert Xu 	if (!node)
7603c8efc1SHerbert Xu 		goto unlock;
7703c8efc1SHerbert Xu 
7803c8efc1SHerbert Xu 	type->ops->owner = THIS_MODULE;
7903c8efc1SHerbert Xu 	node->type = type;
8003c8efc1SHerbert Xu 	list_add(&node->list, &alg_types);
8103c8efc1SHerbert Xu 	err = 0;
8203c8efc1SHerbert Xu 
8303c8efc1SHerbert Xu unlock:
8403c8efc1SHerbert Xu 	up_write(&alg_types_sem);
8503c8efc1SHerbert Xu 
8603c8efc1SHerbert Xu 	return err;
8703c8efc1SHerbert Xu }
8803c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_register_type);
8903c8efc1SHerbert Xu 
9003c8efc1SHerbert Xu int af_alg_unregister_type(const struct af_alg_type *type)
9103c8efc1SHerbert Xu {
9203c8efc1SHerbert Xu 	struct alg_type_list *node;
9303c8efc1SHerbert Xu 	int err = -ENOENT;
9403c8efc1SHerbert Xu 
9503c8efc1SHerbert Xu 	down_write(&alg_types_sem);
9603c8efc1SHerbert Xu 	list_for_each_entry(node, &alg_types, list) {
9703c8efc1SHerbert Xu 		if (strcmp(node->type->name, type->name))
9803c8efc1SHerbert Xu 			continue;
9903c8efc1SHerbert Xu 
10003c8efc1SHerbert Xu 		list_del(&node->list);
10103c8efc1SHerbert Xu 		kfree(node);
10203c8efc1SHerbert Xu 		err = 0;
10303c8efc1SHerbert Xu 		break;
10403c8efc1SHerbert Xu 	}
10503c8efc1SHerbert Xu 	up_write(&alg_types_sem);
10603c8efc1SHerbert Xu 
10703c8efc1SHerbert Xu 	return err;
10803c8efc1SHerbert Xu }
10903c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_unregister_type);
11003c8efc1SHerbert Xu 
11103c8efc1SHerbert Xu static void alg_do_release(const struct af_alg_type *type, void *private)
11203c8efc1SHerbert Xu {
11303c8efc1SHerbert Xu 	if (!type)
11403c8efc1SHerbert Xu 		return;
11503c8efc1SHerbert Xu 
11603c8efc1SHerbert Xu 	type->release(private);
11703c8efc1SHerbert Xu 	module_put(type->owner);
11803c8efc1SHerbert Xu }
11903c8efc1SHerbert Xu 
12003c8efc1SHerbert Xu int af_alg_release(struct socket *sock)
12103c8efc1SHerbert Xu {
12203c8efc1SHerbert Xu 	if (sock->sk)
12303c8efc1SHerbert Xu 		sock_put(sock->sk);
12403c8efc1SHerbert Xu 	return 0;
12503c8efc1SHerbert Xu }
12603c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_release);
12703c8efc1SHerbert Xu 
128*c840ac6aSHerbert Xu void af_alg_release_parent(struct sock *sk)
129*c840ac6aSHerbert Xu {
130*c840ac6aSHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
131*c840ac6aSHerbert Xu 	bool last;
132*c840ac6aSHerbert Xu 
133*c840ac6aSHerbert Xu 	sk = ask->parent;
134*c840ac6aSHerbert Xu 	ask = alg_sk(sk);
135*c840ac6aSHerbert Xu 
136*c840ac6aSHerbert Xu 	lock_sock(sk);
137*c840ac6aSHerbert Xu 	last = !--ask->refcnt;
138*c840ac6aSHerbert Xu 	release_sock(sk);
139*c840ac6aSHerbert Xu 
140*c840ac6aSHerbert Xu 	if (last)
141*c840ac6aSHerbert Xu 		sock_put(sk);
142*c840ac6aSHerbert Xu }
143*c840ac6aSHerbert Xu EXPORT_SYMBOL_GPL(af_alg_release_parent);
144*c840ac6aSHerbert Xu 
14503c8efc1SHerbert Xu static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
14603c8efc1SHerbert Xu {
14715539de5SHerbert Xu 	const u32 forbidden = CRYPTO_ALG_INTERNAL;
14803c8efc1SHerbert Xu 	struct sock *sk = sock->sk;
14903c8efc1SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
15003c8efc1SHerbert Xu 	struct sockaddr_alg *sa = (void *)uaddr;
15103c8efc1SHerbert Xu 	const struct af_alg_type *type;
15203c8efc1SHerbert Xu 	void *private;
153*c840ac6aSHerbert Xu 	int err;
15403c8efc1SHerbert Xu 
15503c8efc1SHerbert Xu 	if (sock->state == SS_CONNECTED)
15603c8efc1SHerbert Xu 		return -EINVAL;
15703c8efc1SHerbert Xu 
15803c8efc1SHerbert Xu 	if (addr_len != sizeof(*sa))
15903c8efc1SHerbert Xu 		return -EINVAL;
16003c8efc1SHerbert Xu 
16103c8efc1SHerbert Xu 	sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
16203c8efc1SHerbert Xu 	sa->salg_name[sizeof(sa->salg_name) - 1] = 0;
16303c8efc1SHerbert Xu 
16403c8efc1SHerbert Xu 	type = alg_get_type(sa->salg_type);
16503c8efc1SHerbert Xu 	if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) {
16603c8efc1SHerbert Xu 		request_module("algif-%s", sa->salg_type);
16703c8efc1SHerbert Xu 		type = alg_get_type(sa->salg_type);
16803c8efc1SHerbert Xu 	}
16903c8efc1SHerbert Xu 
17003c8efc1SHerbert Xu 	if (IS_ERR(type))
17103c8efc1SHerbert Xu 		return PTR_ERR(type);
17203c8efc1SHerbert Xu 
17315539de5SHerbert Xu 	private = type->bind(sa->salg_name,
17415539de5SHerbert Xu 			     sa->salg_feat & ~forbidden,
17515539de5SHerbert Xu 			     sa->salg_mask & ~forbidden);
17603c8efc1SHerbert Xu 	if (IS_ERR(private)) {
17703c8efc1SHerbert Xu 		module_put(type->owner);
17803c8efc1SHerbert Xu 		return PTR_ERR(private);
17903c8efc1SHerbert Xu 	}
18003c8efc1SHerbert Xu 
181*c840ac6aSHerbert Xu 	err = -EBUSY;
18203c8efc1SHerbert Xu 	lock_sock(sk);
183*c840ac6aSHerbert Xu 	if (ask->refcnt)
184*c840ac6aSHerbert Xu 		goto unlock;
18503c8efc1SHerbert Xu 
18603c8efc1SHerbert Xu 	swap(ask->type, type);
18703c8efc1SHerbert Xu 	swap(ask->private, private);
18803c8efc1SHerbert Xu 
189*c840ac6aSHerbert Xu 	err = 0;
190*c840ac6aSHerbert Xu 
191*c840ac6aSHerbert Xu unlock:
19203c8efc1SHerbert Xu 	release_sock(sk);
19303c8efc1SHerbert Xu 
19403c8efc1SHerbert Xu 	alg_do_release(type, private);
19503c8efc1SHerbert Xu 
196*c840ac6aSHerbert Xu 	return err;
19703c8efc1SHerbert Xu }
19803c8efc1SHerbert Xu 
19903c8efc1SHerbert Xu static int alg_setkey(struct sock *sk, char __user *ukey,
20003c8efc1SHerbert Xu 		      unsigned int keylen)
20103c8efc1SHerbert Xu {
20203c8efc1SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
20303c8efc1SHerbert Xu 	const struct af_alg_type *type = ask->type;
20403c8efc1SHerbert Xu 	u8 *key;
20503c8efc1SHerbert Xu 	int err;
20603c8efc1SHerbert Xu 
20703c8efc1SHerbert Xu 	key = sock_kmalloc(sk, keylen, GFP_KERNEL);
20803c8efc1SHerbert Xu 	if (!key)
20903c8efc1SHerbert Xu 		return -ENOMEM;
21003c8efc1SHerbert Xu 
21103c8efc1SHerbert Xu 	err = -EFAULT;
21203c8efc1SHerbert Xu 	if (copy_from_user(key, ukey, keylen))
21303c8efc1SHerbert Xu 		goto out;
21403c8efc1SHerbert Xu 
21503c8efc1SHerbert Xu 	err = type->setkey(ask->private, key, keylen);
21603c8efc1SHerbert Xu 
21703c8efc1SHerbert Xu out:
218ad202c8cSStephan Mueller 	sock_kzfree_s(sk, key, keylen);
21903c8efc1SHerbert Xu 
22003c8efc1SHerbert Xu 	return err;
22103c8efc1SHerbert Xu }
22203c8efc1SHerbert Xu 
22303c8efc1SHerbert Xu static int alg_setsockopt(struct socket *sock, int level, int optname,
22403c8efc1SHerbert Xu 			  char __user *optval, unsigned int optlen)
22503c8efc1SHerbert Xu {
22603c8efc1SHerbert Xu 	struct sock *sk = sock->sk;
22703c8efc1SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
22803c8efc1SHerbert Xu 	const struct af_alg_type *type;
229*c840ac6aSHerbert Xu 	int err = -EBUSY;
23003c8efc1SHerbert Xu 
23103c8efc1SHerbert Xu 	lock_sock(sk);
232*c840ac6aSHerbert Xu 	if (ask->refcnt)
233*c840ac6aSHerbert Xu 		goto unlock;
234*c840ac6aSHerbert Xu 
23503c8efc1SHerbert Xu 	type = ask->type;
23603c8efc1SHerbert Xu 
237*c840ac6aSHerbert Xu 	err = -ENOPROTOOPT;
23803c8efc1SHerbert Xu 	if (level != SOL_ALG || !type)
23903c8efc1SHerbert Xu 		goto unlock;
24003c8efc1SHerbert Xu 
24103c8efc1SHerbert Xu 	switch (optname) {
24203c8efc1SHerbert Xu 	case ALG_SET_KEY:
24303c8efc1SHerbert Xu 		if (sock->state == SS_CONNECTED)
24403c8efc1SHerbert Xu 			goto unlock;
24503c8efc1SHerbert Xu 		if (!type->setkey)
24603c8efc1SHerbert Xu 			goto unlock;
24703c8efc1SHerbert Xu 
24803c8efc1SHerbert Xu 		err = alg_setkey(sk, optval, optlen);
24925fb8638SStephan Mueller 		break;
25025fb8638SStephan Mueller 	case ALG_SET_AEAD_AUTHSIZE:
25125fb8638SStephan Mueller 		if (sock->state == SS_CONNECTED)
25225fb8638SStephan Mueller 			goto unlock;
25325fb8638SStephan Mueller 		if (!type->setauthsize)
25425fb8638SStephan Mueller 			goto unlock;
25525fb8638SStephan Mueller 		err = type->setauthsize(ask->private, optlen);
25603c8efc1SHerbert Xu 	}
25703c8efc1SHerbert Xu 
25803c8efc1SHerbert Xu unlock:
25903c8efc1SHerbert Xu 	release_sock(sk);
26003c8efc1SHerbert Xu 
26103c8efc1SHerbert Xu 	return err;
26203c8efc1SHerbert Xu }
26303c8efc1SHerbert Xu 
26403c8efc1SHerbert Xu int af_alg_accept(struct sock *sk, struct socket *newsock)
26503c8efc1SHerbert Xu {
26603c8efc1SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
26703c8efc1SHerbert Xu 	const struct af_alg_type *type;
26803c8efc1SHerbert Xu 	struct sock *sk2;
26903c8efc1SHerbert Xu 	int err;
27003c8efc1SHerbert Xu 
27103c8efc1SHerbert Xu 	lock_sock(sk);
27203c8efc1SHerbert Xu 	type = ask->type;
27303c8efc1SHerbert Xu 
27403c8efc1SHerbert Xu 	err = -EINVAL;
27503c8efc1SHerbert Xu 	if (!type)
27603c8efc1SHerbert Xu 		goto unlock;
27703c8efc1SHerbert Xu 
27811aa9c28SEric W. Biederman 	sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto, 0);
27903c8efc1SHerbert Xu 	err = -ENOMEM;
28003c8efc1SHerbert Xu 	if (!sk2)
28103c8efc1SHerbert Xu 		goto unlock;
28203c8efc1SHerbert Xu 
28303c8efc1SHerbert Xu 	sock_init_data(newsock, sk2);
284507cad35SMiloslav Trmač 	sock_graft(sk2, newsock);
2854c63f83cSMilan Broz 	security_sk_clone(sk, sk2);
28603c8efc1SHerbert Xu 
28703c8efc1SHerbert Xu 	err = type->accept(ask->private, sk2);
28803c8efc1SHerbert Xu 	if (err) {
28903c8efc1SHerbert Xu 		sk_free(sk2);
29003c8efc1SHerbert Xu 		goto unlock;
29103c8efc1SHerbert Xu 	}
29203c8efc1SHerbert Xu 
29303c8efc1SHerbert Xu 	sk2->sk_family = PF_ALG;
29403c8efc1SHerbert Xu 
295*c840ac6aSHerbert Xu 	if (!ask->refcnt++)
29603c8efc1SHerbert Xu 		sock_hold(sk);
29703c8efc1SHerbert Xu 	alg_sk(sk2)->parent = sk;
29803c8efc1SHerbert Xu 	alg_sk(sk2)->type = type;
29903c8efc1SHerbert Xu 
30003c8efc1SHerbert Xu 	newsock->ops = type->ops;
30103c8efc1SHerbert Xu 	newsock->state = SS_CONNECTED;
30203c8efc1SHerbert Xu 
30303c8efc1SHerbert Xu 	err = 0;
30403c8efc1SHerbert Xu 
30503c8efc1SHerbert Xu unlock:
30603c8efc1SHerbert Xu 	release_sock(sk);
30703c8efc1SHerbert Xu 
30803c8efc1SHerbert Xu 	return err;
30903c8efc1SHerbert Xu }
31003c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_accept);
31103c8efc1SHerbert Xu 
31203c8efc1SHerbert Xu static int alg_accept(struct socket *sock, struct socket *newsock, int flags)
31303c8efc1SHerbert Xu {
31403c8efc1SHerbert Xu 	return af_alg_accept(sock->sk, newsock);
31503c8efc1SHerbert Xu }
31603c8efc1SHerbert Xu 
31703c8efc1SHerbert Xu static const struct proto_ops alg_proto_ops = {
31803c8efc1SHerbert Xu 	.family		=	PF_ALG,
31903c8efc1SHerbert Xu 	.owner		=	THIS_MODULE,
32003c8efc1SHerbert Xu 
32103c8efc1SHerbert Xu 	.connect	=	sock_no_connect,
32203c8efc1SHerbert Xu 	.socketpair	=	sock_no_socketpair,
32303c8efc1SHerbert Xu 	.getname	=	sock_no_getname,
32403c8efc1SHerbert Xu 	.ioctl		=	sock_no_ioctl,
32503c8efc1SHerbert Xu 	.listen		=	sock_no_listen,
32603c8efc1SHerbert Xu 	.shutdown	=	sock_no_shutdown,
32703c8efc1SHerbert Xu 	.getsockopt	=	sock_no_getsockopt,
32803c8efc1SHerbert Xu 	.mmap		=	sock_no_mmap,
32903c8efc1SHerbert Xu 	.sendpage	=	sock_no_sendpage,
33003c8efc1SHerbert Xu 	.sendmsg	=	sock_no_sendmsg,
33103c8efc1SHerbert Xu 	.recvmsg	=	sock_no_recvmsg,
33203c8efc1SHerbert Xu 	.poll		=	sock_no_poll,
33303c8efc1SHerbert Xu 
33403c8efc1SHerbert Xu 	.bind		=	alg_bind,
33503c8efc1SHerbert Xu 	.release	=	af_alg_release,
33603c8efc1SHerbert Xu 	.setsockopt	=	alg_setsockopt,
33703c8efc1SHerbert Xu 	.accept		=	alg_accept,
33803c8efc1SHerbert Xu };
33903c8efc1SHerbert Xu 
34003c8efc1SHerbert Xu static void alg_sock_destruct(struct sock *sk)
34103c8efc1SHerbert Xu {
34203c8efc1SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
34303c8efc1SHerbert Xu 
34403c8efc1SHerbert Xu 	alg_do_release(ask->type, ask->private);
34503c8efc1SHerbert Xu }
34603c8efc1SHerbert Xu 
34703c8efc1SHerbert Xu static int alg_create(struct net *net, struct socket *sock, int protocol,
34803c8efc1SHerbert Xu 		      int kern)
34903c8efc1SHerbert Xu {
35003c8efc1SHerbert Xu 	struct sock *sk;
35103c8efc1SHerbert Xu 	int err;
35203c8efc1SHerbert Xu 
35303c8efc1SHerbert Xu 	if (sock->type != SOCK_SEQPACKET)
35403c8efc1SHerbert Xu 		return -ESOCKTNOSUPPORT;
35503c8efc1SHerbert Xu 	if (protocol != 0)
35603c8efc1SHerbert Xu 		return -EPROTONOSUPPORT;
35703c8efc1SHerbert Xu 
35803c8efc1SHerbert Xu 	err = -ENOMEM;
35911aa9c28SEric W. Biederman 	sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto, kern);
36003c8efc1SHerbert Xu 	if (!sk)
36103c8efc1SHerbert Xu 		goto out;
36203c8efc1SHerbert Xu 
36303c8efc1SHerbert Xu 	sock->ops = &alg_proto_ops;
36403c8efc1SHerbert Xu 	sock_init_data(sock, sk);
36503c8efc1SHerbert Xu 
36603c8efc1SHerbert Xu 	sk->sk_family = PF_ALG;
36703c8efc1SHerbert Xu 	sk->sk_destruct = alg_sock_destruct;
36803c8efc1SHerbert Xu 
36903c8efc1SHerbert Xu 	return 0;
37003c8efc1SHerbert Xu out:
37103c8efc1SHerbert Xu 	return err;
37203c8efc1SHerbert Xu }
37303c8efc1SHerbert Xu 
37403c8efc1SHerbert Xu static const struct net_proto_family alg_family = {
37503c8efc1SHerbert Xu 	.family	=	PF_ALG,
37603c8efc1SHerbert Xu 	.create	=	alg_create,
37703c8efc1SHerbert Xu 	.owner	=	THIS_MODULE,
37803c8efc1SHerbert Xu };
37903c8efc1SHerbert Xu 
3801d10eb2fSAl Viro int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
38103c8efc1SHerbert Xu {
3821d10eb2fSAl Viro 	size_t off;
3831d10eb2fSAl Viro 	ssize_t n;
3841d10eb2fSAl Viro 	int npages, i;
38503c8efc1SHerbert Xu 
3861d10eb2fSAl Viro 	n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
3871d10eb2fSAl Viro 	if (n < 0)
3881d10eb2fSAl Viro 		return n;
38903c8efc1SHerbert Xu 
3909399f0c5SLinus Torvalds 	npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT;
39103c8efc1SHerbert Xu 	if (WARN_ON(npages == 0))
3921d10eb2fSAl Viro 		return -EINVAL;
39366db3739STadeusz Struk 	/* Add one extra for linking */
39466db3739STadeusz Struk 	sg_init_table(sgl->sg, npages + 1);
39503c8efc1SHerbert Xu 
3961d10eb2fSAl Viro 	for (i = 0, len = n; i < npages; i++) {
39703c8efc1SHerbert Xu 		int plen = min_t(int, len, PAGE_SIZE - off);
39803c8efc1SHerbert Xu 
39903c8efc1SHerbert Xu 		sg_set_page(sgl->sg + i, sgl->pages[i], plen, off);
40003c8efc1SHerbert Xu 
40103c8efc1SHerbert Xu 		off = 0;
40203c8efc1SHerbert Xu 		len -= plen;
40303c8efc1SHerbert Xu 	}
40466db3739STadeusz Struk 	sg_mark_end(sgl->sg + npages - 1);
40566db3739STadeusz Struk 	sgl->npages = npages;
40666db3739STadeusz Struk 
4071d10eb2fSAl Viro 	return n;
40803c8efc1SHerbert Xu }
40903c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_make_sg);
41003c8efc1SHerbert Xu 
41166db3739STadeusz Struk void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new)
41266db3739STadeusz Struk {
41366db3739STadeusz Struk 	sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1);
41466db3739STadeusz Struk 	sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg);
41566db3739STadeusz Struk }
416bd507520STadeusz Struk EXPORT_SYMBOL_GPL(af_alg_link_sg);
41766db3739STadeusz Struk 
41803c8efc1SHerbert Xu void af_alg_free_sg(struct af_alg_sgl *sgl)
41903c8efc1SHerbert Xu {
42003c8efc1SHerbert Xu 	int i;
42103c8efc1SHerbert Xu 
42266db3739STadeusz Struk 	for (i = 0; i < sgl->npages; i++)
42303c8efc1SHerbert Xu 		put_page(sgl->pages[i]);
42403c8efc1SHerbert Xu }
42503c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_free_sg);
42603c8efc1SHerbert Xu 
42703c8efc1SHerbert Xu int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con)
42803c8efc1SHerbert Xu {
42903c8efc1SHerbert Xu 	struct cmsghdr *cmsg;
43003c8efc1SHerbert Xu 
431f95b414eSGu Zheng 	for_each_cmsghdr(cmsg, msg) {
43203c8efc1SHerbert Xu 		if (!CMSG_OK(msg, cmsg))
43303c8efc1SHerbert Xu 			return -EINVAL;
43403c8efc1SHerbert Xu 		if (cmsg->cmsg_level != SOL_ALG)
43503c8efc1SHerbert Xu 			continue;
43603c8efc1SHerbert Xu 
43703c8efc1SHerbert Xu 		switch (cmsg->cmsg_type) {
43803c8efc1SHerbert Xu 		case ALG_SET_IV:
43903c8efc1SHerbert Xu 			if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv)))
44003c8efc1SHerbert Xu 				return -EINVAL;
44103c8efc1SHerbert Xu 			con->iv = (void *)CMSG_DATA(cmsg);
44203c8efc1SHerbert Xu 			if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen +
44303c8efc1SHerbert Xu 						      sizeof(*con->iv)))
44403c8efc1SHerbert Xu 				return -EINVAL;
44503c8efc1SHerbert Xu 			break;
44603c8efc1SHerbert Xu 
44703c8efc1SHerbert Xu 		case ALG_SET_OP:
44803c8efc1SHerbert Xu 			if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
44903c8efc1SHerbert Xu 				return -EINVAL;
45003c8efc1SHerbert Xu 			con->op = *(u32 *)CMSG_DATA(cmsg);
45103c8efc1SHerbert Xu 			break;
45203c8efc1SHerbert Xu 
453af8e8073SStephan Mueller 		case ALG_SET_AEAD_ASSOCLEN:
454af8e8073SStephan Mueller 			if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
455af8e8073SStephan Mueller 				return -EINVAL;
456af8e8073SStephan Mueller 			con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg);
457af8e8073SStephan Mueller 			break;
458af8e8073SStephan Mueller 
45903c8efc1SHerbert Xu 		default:
46003c8efc1SHerbert Xu 			return -EINVAL;
46103c8efc1SHerbert Xu 		}
46203c8efc1SHerbert Xu 	}
46303c8efc1SHerbert Xu 
46403c8efc1SHerbert Xu 	return 0;
46503c8efc1SHerbert Xu }
46603c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_cmsg_send);
46703c8efc1SHerbert Xu 
46803c8efc1SHerbert Xu int af_alg_wait_for_completion(int err, struct af_alg_completion *completion)
46903c8efc1SHerbert Xu {
47003c8efc1SHerbert Xu 	switch (err) {
47103c8efc1SHerbert Xu 	case -EINPROGRESS:
47203c8efc1SHerbert Xu 	case -EBUSY:
47303c8efc1SHerbert Xu 		wait_for_completion(&completion->completion);
47416735d02SWolfram Sang 		reinit_completion(&completion->completion);
47503c8efc1SHerbert Xu 		err = completion->err;
47603c8efc1SHerbert Xu 		break;
47703c8efc1SHerbert Xu 	};
47803c8efc1SHerbert Xu 
47903c8efc1SHerbert Xu 	return err;
48003c8efc1SHerbert Xu }
48103c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_wait_for_completion);
48203c8efc1SHerbert Xu 
48303c8efc1SHerbert Xu void af_alg_complete(struct crypto_async_request *req, int err)
48403c8efc1SHerbert Xu {
48503c8efc1SHerbert Xu 	struct af_alg_completion *completion = req->data;
48603c8efc1SHerbert Xu 
4877e77bdebSRabin Vincent 	if (err == -EINPROGRESS)
4887e77bdebSRabin Vincent 		return;
4897e77bdebSRabin Vincent 
49003c8efc1SHerbert Xu 	completion->err = err;
49103c8efc1SHerbert Xu 	complete(&completion->completion);
49203c8efc1SHerbert Xu }
49303c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_complete);
49403c8efc1SHerbert Xu 
49503c8efc1SHerbert Xu static int __init af_alg_init(void)
49603c8efc1SHerbert Xu {
49703c8efc1SHerbert Xu 	int err = proto_register(&alg_proto, 0);
49803c8efc1SHerbert Xu 
49903c8efc1SHerbert Xu 	if (err)
50003c8efc1SHerbert Xu 		goto out;
50103c8efc1SHerbert Xu 
50203c8efc1SHerbert Xu 	err = sock_register(&alg_family);
50303c8efc1SHerbert Xu 	if (err != 0)
50403c8efc1SHerbert Xu 		goto out_unregister_proto;
50503c8efc1SHerbert Xu 
50603c8efc1SHerbert Xu out:
50703c8efc1SHerbert Xu 	return err;
50803c8efc1SHerbert Xu 
50903c8efc1SHerbert Xu out_unregister_proto:
51003c8efc1SHerbert Xu 	proto_unregister(&alg_proto);
51103c8efc1SHerbert Xu 	goto out;
51203c8efc1SHerbert Xu }
51303c8efc1SHerbert Xu 
51403c8efc1SHerbert Xu static void __exit af_alg_exit(void)
51503c8efc1SHerbert Xu {
51603c8efc1SHerbert Xu 	sock_unregister(PF_ALG);
51703c8efc1SHerbert Xu 	proto_unregister(&alg_proto);
51803c8efc1SHerbert Xu }
51903c8efc1SHerbert Xu 
52003c8efc1SHerbert Xu module_init(af_alg_init);
52103c8efc1SHerbert Xu module_exit(af_alg_exit);
52203c8efc1SHerbert Xu MODULE_LICENSE("GPL");
52303c8efc1SHerbert Xu MODULE_ALIAS_NETPROTO(AF_ALG);
524