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