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 1503c8efc1SHerbert Xu #include <asm/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> 2403c8efc1SHerbert Xu 2503c8efc1SHerbert Xu struct alg_type_list { 2603c8efc1SHerbert Xu const struct af_alg_type *type; 2703c8efc1SHerbert Xu struct list_head list; 2803c8efc1SHerbert Xu }; 2903c8efc1SHerbert Xu 3006869524SRandy Dunlap static atomic_long_t alg_memory_allocated; 3103c8efc1SHerbert Xu 3203c8efc1SHerbert Xu static struct proto alg_proto = { 3303c8efc1SHerbert Xu .name = "ALG", 3403c8efc1SHerbert Xu .owner = THIS_MODULE, 3503c8efc1SHerbert Xu .memory_allocated = &alg_memory_allocated, 3603c8efc1SHerbert Xu .obj_size = sizeof(struct alg_sock), 3703c8efc1SHerbert Xu }; 3803c8efc1SHerbert Xu 3903c8efc1SHerbert Xu static LIST_HEAD(alg_types); 4003c8efc1SHerbert Xu static DECLARE_RWSEM(alg_types_sem); 4103c8efc1SHerbert Xu 4203c8efc1SHerbert Xu static const struct af_alg_type *alg_get_type(const char *name) 4303c8efc1SHerbert Xu { 4403c8efc1SHerbert Xu const struct af_alg_type *type = ERR_PTR(-ENOENT); 4503c8efc1SHerbert Xu struct alg_type_list *node; 4603c8efc1SHerbert Xu 4703c8efc1SHerbert Xu down_read(&alg_types_sem); 4803c8efc1SHerbert Xu list_for_each_entry(node, &alg_types, list) { 4903c8efc1SHerbert Xu if (strcmp(node->type->name, name)) 5003c8efc1SHerbert Xu continue; 5103c8efc1SHerbert Xu 5203c8efc1SHerbert Xu if (try_module_get(node->type->owner)) 5303c8efc1SHerbert Xu type = node->type; 5403c8efc1SHerbert Xu break; 5503c8efc1SHerbert Xu } 5603c8efc1SHerbert Xu up_read(&alg_types_sem); 5703c8efc1SHerbert Xu 5803c8efc1SHerbert Xu return type; 5903c8efc1SHerbert Xu } 6003c8efc1SHerbert Xu 6103c8efc1SHerbert Xu int af_alg_register_type(const struct af_alg_type *type) 6203c8efc1SHerbert Xu { 6303c8efc1SHerbert Xu struct alg_type_list *node; 6403c8efc1SHerbert Xu int err = -EEXIST; 6503c8efc1SHerbert Xu 6603c8efc1SHerbert Xu down_write(&alg_types_sem); 6703c8efc1SHerbert Xu list_for_each_entry(node, &alg_types, list) { 6803c8efc1SHerbert Xu if (!strcmp(node->type->name, type->name)) 6903c8efc1SHerbert Xu goto unlock; 7003c8efc1SHerbert Xu } 7103c8efc1SHerbert Xu 7203c8efc1SHerbert Xu node = kmalloc(sizeof(*node), GFP_KERNEL); 7303c8efc1SHerbert Xu err = -ENOMEM; 7403c8efc1SHerbert Xu if (!node) 7503c8efc1SHerbert Xu goto unlock; 7603c8efc1SHerbert Xu 7703c8efc1SHerbert Xu type->ops->owner = THIS_MODULE; 7803c8efc1SHerbert Xu node->type = type; 7903c8efc1SHerbert Xu list_add(&node->list, &alg_types); 8003c8efc1SHerbert Xu err = 0; 8103c8efc1SHerbert Xu 8203c8efc1SHerbert Xu unlock: 8303c8efc1SHerbert Xu up_write(&alg_types_sem); 8403c8efc1SHerbert Xu 8503c8efc1SHerbert Xu return err; 8603c8efc1SHerbert Xu } 8703c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_register_type); 8803c8efc1SHerbert Xu 8903c8efc1SHerbert Xu int af_alg_unregister_type(const struct af_alg_type *type) 9003c8efc1SHerbert Xu { 9103c8efc1SHerbert Xu struct alg_type_list *node; 9203c8efc1SHerbert Xu int err = -ENOENT; 9303c8efc1SHerbert Xu 9403c8efc1SHerbert Xu down_write(&alg_types_sem); 9503c8efc1SHerbert Xu list_for_each_entry(node, &alg_types, list) { 9603c8efc1SHerbert Xu if (strcmp(node->type->name, type->name)) 9703c8efc1SHerbert Xu continue; 9803c8efc1SHerbert Xu 9903c8efc1SHerbert Xu list_del(&node->list); 10003c8efc1SHerbert Xu kfree(node); 10103c8efc1SHerbert Xu err = 0; 10203c8efc1SHerbert Xu break; 10303c8efc1SHerbert Xu } 10403c8efc1SHerbert Xu up_write(&alg_types_sem); 10503c8efc1SHerbert Xu 10603c8efc1SHerbert Xu return err; 10703c8efc1SHerbert Xu } 10803c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_unregister_type); 10903c8efc1SHerbert Xu 11003c8efc1SHerbert Xu static void alg_do_release(const struct af_alg_type *type, void *private) 11103c8efc1SHerbert Xu { 11203c8efc1SHerbert Xu if (!type) 11303c8efc1SHerbert Xu return; 11403c8efc1SHerbert Xu 11503c8efc1SHerbert Xu type->release(private); 11603c8efc1SHerbert Xu module_put(type->owner); 11703c8efc1SHerbert Xu } 11803c8efc1SHerbert Xu 11903c8efc1SHerbert Xu int af_alg_release(struct socket *sock) 12003c8efc1SHerbert Xu { 12103c8efc1SHerbert Xu if (sock->sk) 12203c8efc1SHerbert Xu sock_put(sock->sk); 12303c8efc1SHerbert Xu return 0; 12403c8efc1SHerbert Xu } 12503c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_release); 12603c8efc1SHerbert Xu 12703c8efc1SHerbert Xu static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 12803c8efc1SHerbert Xu { 12903c8efc1SHerbert Xu struct sock *sk = sock->sk; 13003c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 13103c8efc1SHerbert Xu struct sockaddr_alg *sa = (void *)uaddr; 13203c8efc1SHerbert Xu const struct af_alg_type *type; 13303c8efc1SHerbert Xu void *private; 13403c8efc1SHerbert Xu 13503c8efc1SHerbert Xu if (sock->state == SS_CONNECTED) 13603c8efc1SHerbert Xu return -EINVAL; 13703c8efc1SHerbert Xu 13803c8efc1SHerbert Xu if (addr_len != sizeof(*sa)) 13903c8efc1SHerbert Xu return -EINVAL; 14003c8efc1SHerbert Xu 14103c8efc1SHerbert Xu sa->salg_type[sizeof(sa->salg_type) - 1] = 0; 14203c8efc1SHerbert Xu sa->salg_name[sizeof(sa->salg_name) - 1] = 0; 14303c8efc1SHerbert Xu 14403c8efc1SHerbert Xu type = alg_get_type(sa->salg_type); 14503c8efc1SHerbert Xu if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) { 14603c8efc1SHerbert Xu request_module("algif-%s", sa->salg_type); 14703c8efc1SHerbert Xu type = alg_get_type(sa->salg_type); 14803c8efc1SHerbert Xu } 14903c8efc1SHerbert Xu 15003c8efc1SHerbert Xu if (IS_ERR(type)) 15103c8efc1SHerbert Xu return PTR_ERR(type); 15203c8efc1SHerbert Xu 15303c8efc1SHerbert Xu private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask); 15403c8efc1SHerbert Xu if (IS_ERR(private)) { 15503c8efc1SHerbert Xu module_put(type->owner); 15603c8efc1SHerbert Xu return PTR_ERR(private); 15703c8efc1SHerbert Xu } 15803c8efc1SHerbert Xu 15903c8efc1SHerbert Xu lock_sock(sk); 16003c8efc1SHerbert Xu 16103c8efc1SHerbert Xu swap(ask->type, type); 16203c8efc1SHerbert Xu swap(ask->private, private); 16303c8efc1SHerbert Xu 16403c8efc1SHerbert Xu release_sock(sk); 16503c8efc1SHerbert Xu 16603c8efc1SHerbert Xu alg_do_release(type, private); 16703c8efc1SHerbert Xu 16803c8efc1SHerbert Xu return 0; 16903c8efc1SHerbert Xu } 17003c8efc1SHerbert Xu 17103c8efc1SHerbert Xu static int alg_setkey(struct sock *sk, char __user *ukey, 17203c8efc1SHerbert Xu unsigned int keylen) 17303c8efc1SHerbert Xu { 17403c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 17503c8efc1SHerbert Xu const struct af_alg_type *type = ask->type; 17603c8efc1SHerbert Xu u8 *key; 17703c8efc1SHerbert Xu int err; 17803c8efc1SHerbert Xu 17903c8efc1SHerbert Xu key = sock_kmalloc(sk, keylen, GFP_KERNEL); 18003c8efc1SHerbert Xu if (!key) 18103c8efc1SHerbert Xu return -ENOMEM; 18203c8efc1SHerbert Xu 18303c8efc1SHerbert Xu err = -EFAULT; 18403c8efc1SHerbert Xu if (copy_from_user(key, ukey, keylen)) 18503c8efc1SHerbert Xu goto out; 18603c8efc1SHerbert Xu 18703c8efc1SHerbert Xu err = type->setkey(ask->private, key, keylen); 18803c8efc1SHerbert Xu 18903c8efc1SHerbert Xu out: 19003c8efc1SHerbert Xu sock_kfree_s(sk, key, keylen); 19103c8efc1SHerbert Xu 19203c8efc1SHerbert Xu return err; 19303c8efc1SHerbert Xu } 19403c8efc1SHerbert Xu 19503c8efc1SHerbert Xu static int alg_setsockopt(struct socket *sock, int level, int optname, 19603c8efc1SHerbert Xu char __user *optval, unsigned int optlen) 19703c8efc1SHerbert Xu { 19803c8efc1SHerbert Xu struct sock *sk = sock->sk; 19903c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 20003c8efc1SHerbert Xu const struct af_alg_type *type; 20103c8efc1SHerbert Xu int err = -ENOPROTOOPT; 20203c8efc1SHerbert Xu 20303c8efc1SHerbert Xu lock_sock(sk); 20403c8efc1SHerbert Xu type = ask->type; 20503c8efc1SHerbert Xu 20603c8efc1SHerbert Xu if (level != SOL_ALG || !type) 20703c8efc1SHerbert Xu goto unlock; 20803c8efc1SHerbert Xu 20903c8efc1SHerbert Xu switch (optname) { 21003c8efc1SHerbert Xu case ALG_SET_KEY: 21103c8efc1SHerbert Xu if (sock->state == SS_CONNECTED) 21203c8efc1SHerbert Xu goto unlock; 21303c8efc1SHerbert Xu if (!type->setkey) 21403c8efc1SHerbert Xu goto unlock; 21503c8efc1SHerbert Xu 21603c8efc1SHerbert Xu err = alg_setkey(sk, optval, optlen); 21703c8efc1SHerbert Xu } 21803c8efc1SHerbert Xu 21903c8efc1SHerbert Xu unlock: 22003c8efc1SHerbert Xu release_sock(sk); 22103c8efc1SHerbert Xu 22203c8efc1SHerbert Xu return err; 22303c8efc1SHerbert Xu } 22403c8efc1SHerbert Xu 22503c8efc1SHerbert Xu int af_alg_accept(struct sock *sk, struct socket *newsock) 22603c8efc1SHerbert Xu { 22703c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 22803c8efc1SHerbert Xu const struct af_alg_type *type; 22903c8efc1SHerbert Xu struct sock *sk2; 23003c8efc1SHerbert Xu int err; 23103c8efc1SHerbert Xu 23203c8efc1SHerbert Xu lock_sock(sk); 23303c8efc1SHerbert Xu type = ask->type; 23403c8efc1SHerbert Xu 23503c8efc1SHerbert Xu err = -EINVAL; 23603c8efc1SHerbert Xu if (!type) 23703c8efc1SHerbert Xu goto unlock; 23803c8efc1SHerbert Xu 23903c8efc1SHerbert Xu sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto); 24003c8efc1SHerbert Xu err = -ENOMEM; 24103c8efc1SHerbert Xu if (!sk2) 24203c8efc1SHerbert Xu goto unlock; 24303c8efc1SHerbert Xu 24403c8efc1SHerbert Xu sock_init_data(newsock, sk2); 245507cad35SMiloslav Trmač sock_graft(sk2, newsock); 24603c8efc1SHerbert Xu 24703c8efc1SHerbert Xu err = type->accept(ask->private, sk2); 24803c8efc1SHerbert Xu if (err) { 24903c8efc1SHerbert Xu sk_free(sk2); 25003c8efc1SHerbert Xu goto unlock; 25103c8efc1SHerbert Xu } 25203c8efc1SHerbert Xu 25303c8efc1SHerbert Xu sk2->sk_family = PF_ALG; 25403c8efc1SHerbert Xu 25503c8efc1SHerbert Xu sock_hold(sk); 25603c8efc1SHerbert Xu alg_sk(sk2)->parent = sk; 25703c8efc1SHerbert Xu alg_sk(sk2)->type = type; 25803c8efc1SHerbert Xu 25903c8efc1SHerbert Xu newsock->ops = type->ops; 26003c8efc1SHerbert Xu newsock->state = SS_CONNECTED; 26103c8efc1SHerbert Xu 26203c8efc1SHerbert Xu err = 0; 26303c8efc1SHerbert Xu 26403c8efc1SHerbert Xu unlock: 26503c8efc1SHerbert Xu release_sock(sk); 26603c8efc1SHerbert Xu 26703c8efc1SHerbert Xu return err; 26803c8efc1SHerbert Xu } 26903c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_accept); 27003c8efc1SHerbert Xu 27103c8efc1SHerbert Xu static int alg_accept(struct socket *sock, struct socket *newsock, int flags) 27203c8efc1SHerbert Xu { 27303c8efc1SHerbert Xu return af_alg_accept(sock->sk, newsock); 27403c8efc1SHerbert Xu } 27503c8efc1SHerbert Xu 27603c8efc1SHerbert Xu static const struct proto_ops alg_proto_ops = { 27703c8efc1SHerbert Xu .family = PF_ALG, 27803c8efc1SHerbert Xu .owner = THIS_MODULE, 27903c8efc1SHerbert Xu 28003c8efc1SHerbert Xu .connect = sock_no_connect, 28103c8efc1SHerbert Xu .socketpair = sock_no_socketpair, 28203c8efc1SHerbert Xu .getname = sock_no_getname, 28303c8efc1SHerbert Xu .ioctl = sock_no_ioctl, 28403c8efc1SHerbert Xu .listen = sock_no_listen, 28503c8efc1SHerbert Xu .shutdown = sock_no_shutdown, 28603c8efc1SHerbert Xu .getsockopt = sock_no_getsockopt, 28703c8efc1SHerbert Xu .mmap = sock_no_mmap, 28803c8efc1SHerbert Xu .sendpage = sock_no_sendpage, 28903c8efc1SHerbert Xu .sendmsg = sock_no_sendmsg, 29003c8efc1SHerbert Xu .recvmsg = sock_no_recvmsg, 29103c8efc1SHerbert Xu .poll = sock_no_poll, 29203c8efc1SHerbert Xu 29303c8efc1SHerbert Xu .bind = alg_bind, 29403c8efc1SHerbert Xu .release = af_alg_release, 29503c8efc1SHerbert Xu .setsockopt = alg_setsockopt, 29603c8efc1SHerbert Xu .accept = alg_accept, 29703c8efc1SHerbert Xu }; 29803c8efc1SHerbert Xu 29903c8efc1SHerbert Xu static void alg_sock_destruct(struct sock *sk) 30003c8efc1SHerbert Xu { 30103c8efc1SHerbert Xu struct alg_sock *ask = alg_sk(sk); 30203c8efc1SHerbert Xu 30303c8efc1SHerbert Xu alg_do_release(ask->type, ask->private); 30403c8efc1SHerbert Xu } 30503c8efc1SHerbert Xu 30603c8efc1SHerbert Xu static int alg_create(struct net *net, struct socket *sock, int protocol, 30703c8efc1SHerbert Xu int kern) 30803c8efc1SHerbert Xu { 30903c8efc1SHerbert Xu struct sock *sk; 31003c8efc1SHerbert Xu int err; 31103c8efc1SHerbert Xu 31203c8efc1SHerbert Xu if (sock->type != SOCK_SEQPACKET) 31303c8efc1SHerbert Xu return -ESOCKTNOSUPPORT; 31403c8efc1SHerbert Xu if (protocol != 0) 31503c8efc1SHerbert Xu return -EPROTONOSUPPORT; 31603c8efc1SHerbert Xu 31703c8efc1SHerbert Xu err = -ENOMEM; 31803c8efc1SHerbert Xu sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto); 31903c8efc1SHerbert Xu if (!sk) 32003c8efc1SHerbert Xu goto out; 32103c8efc1SHerbert Xu 32203c8efc1SHerbert Xu sock->ops = &alg_proto_ops; 32303c8efc1SHerbert Xu sock_init_data(sock, sk); 32403c8efc1SHerbert Xu 32503c8efc1SHerbert Xu sk->sk_family = PF_ALG; 32603c8efc1SHerbert Xu sk->sk_destruct = alg_sock_destruct; 32703c8efc1SHerbert Xu 32803c8efc1SHerbert Xu return 0; 32903c8efc1SHerbert Xu out: 33003c8efc1SHerbert Xu return err; 33103c8efc1SHerbert Xu } 33203c8efc1SHerbert Xu 33303c8efc1SHerbert Xu static const struct net_proto_family alg_family = { 33403c8efc1SHerbert Xu .family = PF_ALG, 33503c8efc1SHerbert Xu .create = alg_create, 33603c8efc1SHerbert Xu .owner = THIS_MODULE, 33703c8efc1SHerbert Xu }; 33803c8efc1SHerbert Xu 33903c8efc1SHerbert Xu int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, 34003c8efc1SHerbert Xu int write) 34103c8efc1SHerbert Xu { 34203c8efc1SHerbert Xu unsigned long from = (unsigned long)addr; 34303c8efc1SHerbert Xu unsigned long npages; 34403c8efc1SHerbert Xu unsigned off; 34503c8efc1SHerbert Xu int err; 34603c8efc1SHerbert Xu int i; 34703c8efc1SHerbert Xu 34803c8efc1SHerbert Xu err = -EFAULT; 34903c8efc1SHerbert Xu if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len)) 35003c8efc1SHerbert Xu goto out; 35103c8efc1SHerbert Xu 35203c8efc1SHerbert Xu off = from & ~PAGE_MASK; 35303c8efc1SHerbert Xu npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; 35403c8efc1SHerbert Xu if (npages > ALG_MAX_PAGES) 35503c8efc1SHerbert Xu npages = ALG_MAX_PAGES; 35603c8efc1SHerbert Xu 35703c8efc1SHerbert Xu err = get_user_pages_fast(from, npages, write, sgl->pages); 35803c8efc1SHerbert Xu if (err < 0) 35903c8efc1SHerbert Xu goto out; 36003c8efc1SHerbert Xu 36103c8efc1SHerbert Xu npages = err; 36203c8efc1SHerbert Xu err = -EINVAL; 36303c8efc1SHerbert Xu if (WARN_ON(npages == 0)) 36403c8efc1SHerbert Xu goto out; 36503c8efc1SHerbert Xu 36603c8efc1SHerbert Xu err = 0; 36703c8efc1SHerbert Xu 36803c8efc1SHerbert Xu sg_init_table(sgl->sg, npages); 36903c8efc1SHerbert Xu 37003c8efc1SHerbert Xu for (i = 0; i < npages; i++) { 37103c8efc1SHerbert Xu int plen = min_t(int, len, PAGE_SIZE - off); 37203c8efc1SHerbert Xu 37303c8efc1SHerbert Xu sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); 37403c8efc1SHerbert Xu 37503c8efc1SHerbert Xu off = 0; 37603c8efc1SHerbert Xu len -= plen; 37703c8efc1SHerbert Xu err += plen; 37803c8efc1SHerbert Xu } 37903c8efc1SHerbert Xu 38003c8efc1SHerbert Xu out: 38103c8efc1SHerbert Xu return err; 38203c8efc1SHerbert Xu } 38303c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_make_sg); 38403c8efc1SHerbert Xu 38503c8efc1SHerbert Xu void af_alg_free_sg(struct af_alg_sgl *sgl) 38603c8efc1SHerbert Xu { 38703c8efc1SHerbert Xu int i; 38803c8efc1SHerbert Xu 38903c8efc1SHerbert Xu i = 0; 39003c8efc1SHerbert Xu do { 39103c8efc1SHerbert Xu put_page(sgl->pages[i]); 39203c8efc1SHerbert Xu } while (!sg_is_last(sgl->sg + (i++))); 39303c8efc1SHerbert Xu } 39403c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_free_sg); 39503c8efc1SHerbert Xu 39603c8efc1SHerbert Xu int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) 39703c8efc1SHerbert Xu { 39803c8efc1SHerbert Xu struct cmsghdr *cmsg; 39903c8efc1SHerbert Xu 40003c8efc1SHerbert Xu for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 40103c8efc1SHerbert Xu if (!CMSG_OK(msg, cmsg)) 40203c8efc1SHerbert Xu return -EINVAL; 40303c8efc1SHerbert Xu if (cmsg->cmsg_level != SOL_ALG) 40403c8efc1SHerbert Xu continue; 40503c8efc1SHerbert Xu 40603c8efc1SHerbert Xu switch(cmsg->cmsg_type) { 40703c8efc1SHerbert Xu case ALG_SET_IV: 40803c8efc1SHerbert Xu if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv))) 40903c8efc1SHerbert Xu return -EINVAL; 41003c8efc1SHerbert Xu con->iv = (void *)CMSG_DATA(cmsg); 41103c8efc1SHerbert Xu if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen + 41203c8efc1SHerbert Xu sizeof(*con->iv))) 41303c8efc1SHerbert Xu return -EINVAL; 41403c8efc1SHerbert Xu break; 41503c8efc1SHerbert Xu 41603c8efc1SHerbert Xu case ALG_SET_OP: 41703c8efc1SHerbert Xu if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) 41803c8efc1SHerbert Xu return -EINVAL; 41903c8efc1SHerbert Xu con->op = *(u32 *)CMSG_DATA(cmsg); 42003c8efc1SHerbert Xu break; 42103c8efc1SHerbert Xu 42203c8efc1SHerbert Xu default: 42303c8efc1SHerbert Xu return -EINVAL; 42403c8efc1SHerbert Xu } 42503c8efc1SHerbert Xu } 42603c8efc1SHerbert Xu 42703c8efc1SHerbert Xu return 0; 42803c8efc1SHerbert Xu } 42903c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_cmsg_send); 43003c8efc1SHerbert Xu 43103c8efc1SHerbert Xu int af_alg_wait_for_completion(int err, struct af_alg_completion *completion) 43203c8efc1SHerbert Xu { 43303c8efc1SHerbert Xu switch (err) { 43403c8efc1SHerbert Xu case -EINPROGRESS: 43503c8efc1SHerbert Xu case -EBUSY: 43603c8efc1SHerbert Xu wait_for_completion(&completion->completion); 43703c8efc1SHerbert Xu INIT_COMPLETION(completion->completion); 43803c8efc1SHerbert Xu err = completion->err; 43903c8efc1SHerbert Xu break; 44003c8efc1SHerbert Xu }; 44103c8efc1SHerbert Xu 44203c8efc1SHerbert Xu return err; 44303c8efc1SHerbert Xu } 44403c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_wait_for_completion); 44503c8efc1SHerbert Xu 44603c8efc1SHerbert Xu void af_alg_complete(struct crypto_async_request *req, int err) 44703c8efc1SHerbert Xu { 44803c8efc1SHerbert Xu struct af_alg_completion *completion = req->data; 44903c8efc1SHerbert Xu 45003c8efc1SHerbert Xu completion->err = err; 45103c8efc1SHerbert Xu complete(&completion->completion); 45203c8efc1SHerbert Xu } 45303c8efc1SHerbert Xu EXPORT_SYMBOL_GPL(af_alg_complete); 45403c8efc1SHerbert Xu 45503c8efc1SHerbert Xu static int __init af_alg_init(void) 45603c8efc1SHerbert Xu { 45703c8efc1SHerbert Xu int err = proto_register(&alg_proto, 0); 45803c8efc1SHerbert Xu 45903c8efc1SHerbert Xu if (err) 46003c8efc1SHerbert Xu goto out; 46103c8efc1SHerbert Xu 46203c8efc1SHerbert Xu err = sock_register(&alg_family); 46303c8efc1SHerbert Xu if (err != 0) 46403c8efc1SHerbert Xu goto out_unregister_proto; 46503c8efc1SHerbert Xu 46603c8efc1SHerbert Xu out: 46703c8efc1SHerbert Xu return err; 46803c8efc1SHerbert Xu 46903c8efc1SHerbert Xu out_unregister_proto: 47003c8efc1SHerbert Xu proto_unregister(&alg_proto); 47103c8efc1SHerbert Xu goto out; 47203c8efc1SHerbert Xu } 47303c8efc1SHerbert Xu 47403c8efc1SHerbert Xu static void __exit af_alg_exit(void) 47503c8efc1SHerbert Xu { 47603c8efc1SHerbert Xu sock_unregister(PF_ALG); 47703c8efc1SHerbert Xu proto_unregister(&alg_proto); 47803c8efc1SHerbert Xu } 47903c8efc1SHerbert Xu 48003c8efc1SHerbert Xu module_init(af_alg_init); 48103c8efc1SHerbert Xu module_exit(af_alg_exit); 48203c8efc1SHerbert Xu MODULE_LICENSE("GPL"); 48303c8efc1SHerbert Xu MODULE_ALIAS_NETPROTO(AF_ALG); 484