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 12803c8efc1SHerbert Xu static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 12903c8efc1SHerbert Xu { 13003c8efc1SHerbert Xu struct sock *sk = sock->sk; 13103c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 13203c8efc1SHerbert Xu struct sockaddr_alg *sa = (void *)uaddr; 13303c8efc1SHerbert Xu const struct af_alg_type *type; 13403c8efc1SHerbert Xu void *private; 13503c8efc1SHerbert Xu 13603c8efc1SHerbert Xu if (sock->state == SS_CONNECTED) 13703c8efc1SHerbert Xu return -EINVAL; 13803c8efc1SHerbert Xu 13903c8efc1SHerbert Xu if (addr_len != sizeof(*sa)) 14003c8efc1SHerbert Xu return -EINVAL; 14103c8efc1SHerbert Xu 14203c8efc1SHerbert Xu sa->salg_type[sizeof(sa->salg_type) - 1] = 0; 14303c8efc1SHerbert Xu sa->salg_name[sizeof(sa->salg_name) - 1] = 0; 14403c8efc1SHerbert Xu 14503c8efc1SHerbert Xu type = alg_get_type(sa->salg_type); 14603c8efc1SHerbert Xu if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) { 14703c8efc1SHerbert Xu request_module("algif-%s", sa->salg_type); 14803c8efc1SHerbert Xu type = alg_get_type(sa->salg_type); 14903c8efc1SHerbert Xu } 15003c8efc1SHerbert Xu 15103c8efc1SHerbert Xu if (IS_ERR(type)) 15203c8efc1SHerbert Xu return PTR_ERR(type); 15303c8efc1SHerbert Xu 15403c8efc1SHerbert Xu private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask); 15503c8efc1SHerbert Xu if (IS_ERR(private)) { 15603c8efc1SHerbert Xu module_put(type->owner); 15703c8efc1SHerbert Xu return PTR_ERR(private); 15803c8efc1SHerbert Xu } 15903c8efc1SHerbert Xu 16003c8efc1SHerbert Xu lock_sock(sk); 16103c8efc1SHerbert Xu 16203c8efc1SHerbert Xu swap(ask->type, type); 16303c8efc1SHerbert Xu swap(ask->private, private); 16403c8efc1SHerbert Xu 16503c8efc1SHerbert Xu release_sock(sk); 16603c8efc1SHerbert Xu 16703c8efc1SHerbert Xu alg_do_release(type, private); 16803c8efc1SHerbert Xu 16903c8efc1SHerbert Xu return 0; 17003c8efc1SHerbert Xu } 17103c8efc1SHerbert Xu 17203c8efc1SHerbert Xu static int alg_setkey(struct sock *sk, char __user *ukey, 17303c8efc1SHerbert Xu unsigned int keylen) 17403c8efc1SHerbert Xu { 17503c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 17603c8efc1SHerbert Xu const struct af_alg_type *type = ask->type; 17703c8efc1SHerbert Xu u8 *key; 17803c8efc1SHerbert Xu int err; 17903c8efc1SHerbert Xu 18003c8efc1SHerbert Xu key = sock_kmalloc(sk, keylen, GFP_KERNEL); 18103c8efc1SHerbert Xu if (!key) 18203c8efc1SHerbert Xu return -ENOMEM; 18303c8efc1SHerbert Xu 18403c8efc1SHerbert Xu err = -EFAULT; 18503c8efc1SHerbert Xu if (copy_from_user(key, ukey, keylen)) 18603c8efc1SHerbert Xu goto out; 18703c8efc1SHerbert Xu 18803c8efc1SHerbert Xu err = type->setkey(ask->private, key, keylen); 18903c8efc1SHerbert Xu 19003c8efc1SHerbert Xu out: 19103c8efc1SHerbert Xu sock_kfree_s(sk, key, keylen); 19203c8efc1SHerbert Xu 19303c8efc1SHerbert Xu return err; 19403c8efc1SHerbert Xu } 19503c8efc1SHerbert Xu 19603c8efc1SHerbert Xu static int alg_setsockopt(struct socket *sock, int level, int optname, 19703c8efc1SHerbert Xu char __user *optval, unsigned int optlen) 19803c8efc1SHerbert Xu { 19903c8efc1SHerbert Xu struct sock *sk = sock->sk; 20003c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 20103c8efc1SHerbert Xu const struct af_alg_type *type; 20203c8efc1SHerbert Xu int err = -ENOPROTOOPT; 20303c8efc1SHerbert Xu 20403c8efc1SHerbert Xu lock_sock(sk); 20503c8efc1SHerbert Xu type = ask->type; 20603c8efc1SHerbert Xu 20703c8efc1SHerbert Xu if (level != SOL_ALG || !type) 20803c8efc1SHerbert Xu goto unlock; 20903c8efc1SHerbert Xu 21003c8efc1SHerbert Xu switch (optname) { 21103c8efc1SHerbert Xu case ALG_SET_KEY: 21203c8efc1SHerbert Xu if (sock->state == SS_CONNECTED) 21303c8efc1SHerbert Xu goto unlock; 21403c8efc1SHerbert Xu if (!type->setkey) 21503c8efc1SHerbert Xu goto unlock; 21603c8efc1SHerbert Xu 21703c8efc1SHerbert Xu err = alg_setkey(sk, optval, optlen); 21803c8efc1SHerbert Xu } 21903c8efc1SHerbert Xu 22003c8efc1SHerbert Xu unlock: 22103c8efc1SHerbert Xu release_sock(sk); 22203c8efc1SHerbert Xu 22303c8efc1SHerbert Xu return err; 22403c8efc1SHerbert Xu } 22503c8efc1SHerbert Xu 22603c8efc1SHerbert Xu int af_alg_accept(struct sock *sk, struct socket *newsock) 22703c8efc1SHerbert Xu { 22803c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 22903c8efc1SHerbert Xu const struct af_alg_type *type; 23003c8efc1SHerbert Xu struct sock *sk2; 23103c8efc1SHerbert Xu int err; 23203c8efc1SHerbert Xu 23303c8efc1SHerbert Xu lock_sock(sk); 23403c8efc1SHerbert Xu type = ask->type; 23503c8efc1SHerbert Xu 23603c8efc1SHerbert Xu err = -EINVAL; 23703c8efc1SHerbert Xu if (!type) 23803c8efc1SHerbert Xu goto unlock; 23903c8efc1SHerbert Xu 24003c8efc1SHerbert Xu sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto); 24103c8efc1SHerbert Xu err = -ENOMEM; 24203c8efc1SHerbert Xu if (!sk2) 24303c8efc1SHerbert Xu goto unlock; 24403c8efc1SHerbert Xu 24503c8efc1SHerbert Xu sock_init_data(newsock, sk2); 246507cad35SMiloslav Trmač sock_graft(sk2, newsock); 2474c63f83cSMilan Broz security_sk_clone(sk, sk2); 24803c8efc1SHerbert Xu 24903c8efc1SHerbert Xu err = type->accept(ask->private, sk2); 25003c8efc1SHerbert Xu if (err) { 25103c8efc1SHerbert Xu sk_free(sk2); 25203c8efc1SHerbert Xu goto unlock; 25303c8efc1SHerbert Xu } 25403c8efc1SHerbert Xu 25503c8efc1SHerbert Xu sk2->sk_family = PF_ALG; 25603c8efc1SHerbert Xu 25703c8efc1SHerbert Xu sock_hold(sk); 25803c8efc1SHerbert Xu alg_sk(sk2)->parent = sk; 25903c8efc1SHerbert Xu alg_sk(sk2)->type = type; 26003c8efc1SHerbert Xu 26103c8efc1SHerbert Xu newsock->ops = type->ops; 26203c8efc1SHerbert Xu newsock->state = SS_CONNECTED; 26303c8efc1SHerbert Xu 26403c8efc1SHerbert Xu err = 0; 26503c8efc1SHerbert Xu 26603c8efc1SHerbert Xu unlock: 26703c8efc1SHerbert Xu release_sock(sk); 26803c8efc1SHerbert Xu 26903c8efc1SHerbert Xu return err; 27003c8efc1SHerbert Xu } 27103c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_accept); 27203c8efc1SHerbert Xu 27303c8efc1SHerbert Xu static int alg_accept(struct socket *sock, struct socket *newsock, int flags) 27403c8efc1SHerbert Xu { 27503c8efc1SHerbert Xu return af_alg_accept(sock->sk, newsock); 27603c8efc1SHerbert Xu } 27703c8efc1SHerbert Xu 27803c8efc1SHerbert Xu static const struct proto_ops alg_proto_ops = { 27903c8efc1SHerbert Xu .family = PF_ALG, 28003c8efc1SHerbert Xu .owner = THIS_MODULE, 28103c8efc1SHerbert Xu 28203c8efc1SHerbert Xu .connect = sock_no_connect, 28303c8efc1SHerbert Xu .socketpair = sock_no_socketpair, 28403c8efc1SHerbert Xu .getname = sock_no_getname, 28503c8efc1SHerbert Xu .ioctl = sock_no_ioctl, 28603c8efc1SHerbert Xu .listen = sock_no_listen, 28703c8efc1SHerbert Xu .shutdown = sock_no_shutdown, 28803c8efc1SHerbert Xu .getsockopt = sock_no_getsockopt, 28903c8efc1SHerbert Xu .mmap = sock_no_mmap, 29003c8efc1SHerbert Xu .sendpage = sock_no_sendpage, 29103c8efc1SHerbert Xu .sendmsg = sock_no_sendmsg, 29203c8efc1SHerbert Xu .recvmsg = sock_no_recvmsg, 29303c8efc1SHerbert Xu .poll = sock_no_poll, 29403c8efc1SHerbert Xu 29503c8efc1SHerbert Xu .bind = alg_bind, 29603c8efc1SHerbert Xu .release = af_alg_release, 29703c8efc1SHerbert Xu .setsockopt = alg_setsockopt, 29803c8efc1SHerbert Xu .accept = alg_accept, 29903c8efc1SHerbert Xu }; 30003c8efc1SHerbert Xu 30103c8efc1SHerbert Xu static void alg_sock_destruct(struct sock *sk) 30203c8efc1SHerbert Xu { 30303c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 30403c8efc1SHerbert Xu 30503c8efc1SHerbert Xu alg_do_release(ask->type, ask->private); 30603c8efc1SHerbert Xu } 30703c8efc1SHerbert Xu 30803c8efc1SHerbert Xu static int alg_create(struct net *net, struct socket *sock, int protocol, 30903c8efc1SHerbert Xu int kern) 31003c8efc1SHerbert Xu { 31103c8efc1SHerbert Xu struct sock *sk; 31203c8efc1SHerbert Xu int err; 31303c8efc1SHerbert Xu 31403c8efc1SHerbert Xu if (sock->type != SOCK_SEQPACKET) 31503c8efc1SHerbert Xu return -ESOCKTNOSUPPORT; 31603c8efc1SHerbert Xu if (protocol != 0) 31703c8efc1SHerbert Xu return -EPROTONOSUPPORT; 31803c8efc1SHerbert Xu 31903c8efc1SHerbert Xu err = -ENOMEM; 32003c8efc1SHerbert Xu sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto); 32103c8efc1SHerbert Xu if (!sk) 32203c8efc1SHerbert Xu goto out; 32303c8efc1SHerbert Xu 32403c8efc1SHerbert Xu sock->ops = &alg_proto_ops; 32503c8efc1SHerbert Xu sock_init_data(sock, sk); 32603c8efc1SHerbert Xu 32703c8efc1SHerbert Xu sk->sk_family = PF_ALG; 32803c8efc1SHerbert Xu sk->sk_destruct = alg_sock_destruct; 32903c8efc1SHerbert Xu 33003c8efc1SHerbert Xu return 0; 33103c8efc1SHerbert Xu out: 33203c8efc1SHerbert Xu return err; 33303c8efc1SHerbert Xu } 33403c8efc1SHerbert Xu 33503c8efc1SHerbert Xu static const struct net_proto_family alg_family = { 33603c8efc1SHerbert Xu .family = PF_ALG, 33703c8efc1SHerbert Xu .create = alg_create, 33803c8efc1SHerbert Xu .owner = THIS_MODULE, 33903c8efc1SHerbert Xu }; 34003c8efc1SHerbert Xu 3411d10eb2fSAl Viro int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len) 34203c8efc1SHerbert Xu { 3431d10eb2fSAl Viro size_t off; 3441d10eb2fSAl Viro ssize_t n; 3451d10eb2fSAl Viro int npages, i; 34603c8efc1SHerbert Xu 3471d10eb2fSAl Viro n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off); 3481d10eb2fSAl Viro if (n < 0) 3491d10eb2fSAl Viro return n; 35003c8efc1SHerbert Xu 3519399f0c5SLinus Torvalds npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT; 35203c8efc1SHerbert Xu if (WARN_ON(npages == 0)) 3531d10eb2fSAl Viro return -EINVAL; 35403c8efc1SHerbert Xu 35503c8efc1SHerbert Xu sg_init_table(sgl->sg, npages); 35603c8efc1SHerbert Xu 3571d10eb2fSAl Viro for (i = 0, len = n; i < npages; i++) { 35803c8efc1SHerbert Xu int plen = min_t(int, len, PAGE_SIZE - off); 35903c8efc1SHerbert Xu 36003c8efc1SHerbert Xu sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); 36103c8efc1SHerbert Xu 36203c8efc1SHerbert Xu off = 0; 36303c8efc1SHerbert Xu len -= plen; 36403c8efc1SHerbert Xu } 3651d10eb2fSAl Viro return n; 36603c8efc1SHerbert Xu } 36703c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_make_sg); 36803c8efc1SHerbert Xu 36903c8efc1SHerbert Xu void af_alg_free_sg(struct af_alg_sgl *sgl) 37003c8efc1SHerbert Xu { 37103c8efc1SHerbert Xu int i; 37203c8efc1SHerbert Xu 37303c8efc1SHerbert Xu i = 0; 37403c8efc1SHerbert Xu do { 37503c8efc1SHerbert Xu put_page(sgl->pages[i]); 37603c8efc1SHerbert Xu } while (!sg_is_last(sgl->sg + (i++))); 37703c8efc1SHerbert Xu } 37803c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_free_sg); 37903c8efc1SHerbert Xu 38003c8efc1SHerbert Xu int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) 38103c8efc1SHerbert Xu { 38203c8efc1SHerbert Xu struct cmsghdr *cmsg; 38303c8efc1SHerbert Xu 384f95b414eSGu Zheng for_each_cmsghdr(cmsg, msg) { 38503c8efc1SHerbert Xu if (!CMSG_OK(msg, cmsg)) 38603c8efc1SHerbert Xu return -EINVAL; 38703c8efc1SHerbert Xu if (cmsg->cmsg_level != SOL_ALG) 38803c8efc1SHerbert Xu continue; 38903c8efc1SHerbert Xu 39003c8efc1SHerbert Xu switch(cmsg->cmsg_type) { 39103c8efc1SHerbert Xu case ALG_SET_IV: 39203c8efc1SHerbert Xu if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv))) 39303c8efc1SHerbert Xu return -EINVAL; 39403c8efc1SHerbert Xu con->iv = (void *)CMSG_DATA(cmsg); 39503c8efc1SHerbert Xu if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen + 39603c8efc1SHerbert Xu sizeof(*con->iv))) 39703c8efc1SHerbert Xu return -EINVAL; 39803c8efc1SHerbert Xu break; 39903c8efc1SHerbert Xu 40003c8efc1SHerbert Xu case ALG_SET_OP: 40103c8efc1SHerbert Xu if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) 40203c8efc1SHerbert Xu return -EINVAL; 40303c8efc1SHerbert Xu con->op = *(u32 *)CMSG_DATA(cmsg); 40403c8efc1SHerbert Xu break; 40503c8efc1SHerbert Xu 406af8e8073SStephan Mueller case ALG_SET_AEAD_ASSOCLEN: 407af8e8073SStephan Mueller if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) 408af8e8073SStephan Mueller return -EINVAL; 409af8e8073SStephan Mueller con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg); 410af8e8073SStephan Mueller break; 411af8e8073SStephan Mueller 41203c8efc1SHerbert Xu default: 41303c8efc1SHerbert Xu return -EINVAL; 41403c8efc1SHerbert Xu } 41503c8efc1SHerbert Xu } 41603c8efc1SHerbert Xu 41703c8efc1SHerbert Xu return 0; 41803c8efc1SHerbert Xu } 41903c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_cmsg_send); 42003c8efc1SHerbert Xu 42103c8efc1SHerbert Xu int af_alg_wait_for_completion(int err, struct af_alg_completion *completion) 42203c8efc1SHerbert Xu { 42303c8efc1SHerbert Xu switch (err) { 42403c8efc1SHerbert Xu case -EINPROGRESS: 42503c8efc1SHerbert Xu case -EBUSY: 42603c8efc1SHerbert Xu wait_for_completion(&completion->completion); 42716735d02SWolfram Sang reinit_completion(&completion->completion); 42803c8efc1SHerbert Xu err = completion->err; 42903c8efc1SHerbert Xu break; 43003c8efc1SHerbert Xu }; 43103c8efc1SHerbert Xu 43203c8efc1SHerbert Xu return err; 43303c8efc1SHerbert Xu } 43403c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_wait_for_completion); 43503c8efc1SHerbert Xu 43603c8efc1SHerbert Xu void af_alg_complete(struct crypto_async_request *req, int err) 43703c8efc1SHerbert Xu { 43803c8efc1SHerbert Xu struct af_alg_completion *completion = req->data; 43903c8efc1SHerbert Xu 4407e77bdebSRabin Vincent if (err == -EINPROGRESS) 4417e77bdebSRabin Vincent return; 4427e77bdebSRabin Vincent 44303c8efc1SHerbert Xu completion->err = err; 44403c8efc1SHerbert Xu complete(&completion->completion); 44503c8efc1SHerbert Xu } 44603c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_complete); 44703c8efc1SHerbert Xu 44803c8efc1SHerbert Xu static int __init af_alg_init(void) 44903c8efc1SHerbert Xu { 45003c8efc1SHerbert Xu int err = proto_register(&alg_proto, 0); 45103c8efc1SHerbert Xu 45203c8efc1SHerbert Xu if (err) 45303c8efc1SHerbert Xu goto out; 45403c8efc1SHerbert Xu 45503c8efc1SHerbert Xu err = sock_register(&alg_family); 45603c8efc1SHerbert Xu if (err != 0) 45703c8efc1SHerbert Xu goto out_unregister_proto; 45803c8efc1SHerbert Xu 45903c8efc1SHerbert Xu out: 46003c8efc1SHerbert Xu return err; 46103c8efc1SHerbert Xu 46203c8efc1SHerbert Xu out_unregister_proto: 46303c8efc1SHerbert Xu proto_unregister(&alg_proto); 46403c8efc1SHerbert Xu goto out; 46503c8efc1SHerbert Xu } 46603c8efc1SHerbert Xu 46703c8efc1SHerbert Xu static void __exit af_alg_exit(void) 46803c8efc1SHerbert Xu { 46903c8efc1SHerbert Xu sock_unregister(PF_ALG); 47003c8efc1SHerbert Xu proto_unregister(&alg_proto); 47103c8efc1SHerbert Xu } 47203c8efc1SHerbert Xu 47303c8efc1SHerbert Xu module_init(af_alg_init); 47403c8efc1SHerbert Xu module_exit(af_alg_exit); 47503c8efc1SHerbert Xu MODULE_LICENSE("GPL"); 47603c8efc1SHerbert Xu MODULE_ALIAS_NETPROTO(AF_ALG); 477