summaryrefslogtreecommitdiffstats
path: root/cryptodev_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'cryptodev_main.c')
-rw-r--r--cryptodev_main.c82
1 files changed, 53 insertions, 29 deletions
diff --git a/cryptodev_main.c b/cryptodev_main.c
index 93bb676..73e2586 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -114,9 +114,11 @@ enum alg_op_type {
struct alg_sock {
struct sock sk;
- /* enum alg_op_type; Only changes once, from OP_NONE */
+ /* enum alg_op_type; Only changes once, from OP_NONE; alg_sock::mutex
+ protects the transition. */
atomic_t op_type;
+ struct mutex mutex; /* Protects everything below */
struct data_sock *slaves[1];
unsigned num_slaves, accept_idx;
struct hash_data hash;
@@ -322,8 +324,6 @@ static int do_data_sendmsg(struct kiocb *iocb, struct alg_sock *ask,
char *buf;
int res;
- // FIXME: locking
-
DUMP_ASK(ask);
switch (ask_op_type(ask)) {
@@ -341,7 +341,9 @@ static int do_data_sendmsg(struct kiocb *iocb, struct alg_sock *ask,
if (res != 0)
goto err;
+ mutex_lock(&ask->mutex);
res = _cryptodev_hash_update(&ask->hash, buf, total_len);
+ mutex_unlock(&ask->mutex);
if (res < 0)
goto err;
@@ -372,8 +374,6 @@ static int do_data_recvmsg(struct kiocb *iocb, struct alg_sock *ask,
unsigned index, struct msghdr *m, size_t total_len,
int flags)
{
- // FIXME: locking
-
DUMP_ASK(ask);
switch (ask_op_type(ask)) {
@@ -388,7 +388,11 @@ static int do_data_recvmsg(struct kiocb *iocb, struct alg_sock *ask,
return -EINVAL;
BUG_ON(ask->hash.digestsize > sizeof(digest));
+ mutex_lock(&ask->mutex);
res = cryptodev_hash_final(&ask->hash, digest);
+ if (res >= 0)
+ res = cryptodev_hash_reset(&ask->hash);
+ mutex_unlock(&ask->mutex);
if (res < 0)
return res;
@@ -396,10 +400,6 @@ static int do_data_recvmsg(struct kiocb *iocb, struct alg_sock *ask,
if (res != 0)
return res;
- res = cryptodev_hash_reset(&ask->hash);
- if (res != 0)
- return res;
-
return ask->hash.digestsize;
}
@@ -459,6 +459,7 @@ static void alg_destruct(struct sock *sk)
break;
case OP_HASH:
+ /* Locking is not necessary, this is the only reference. */
cryptodev_hash_deinit(&ask->hash);
break;
@@ -469,6 +470,8 @@ static void alg_destruct(struct sock *sk)
local_bh_disable();
sock_prot_inuse_add(sock_net(sk), &alg_proto, -1);
local_bh_enable();
+
+ mutex_destroy(&ask->mutex);
DUMP_ASK(ask);
}
@@ -489,6 +492,8 @@ static int alg_release(struct socket *sock)
// skb_queue_purge(&sk->sk_write_queue);???
+ /* Locking ask->mutex is not necessary here, ask->{slaves,num_slaves,
+ accept_idx} can only be manipulated through sock. */
for (i = 0; i < ask->num_slaves; i++) {
struct data_sock *dsk;
@@ -526,22 +531,28 @@ static int alg_bind(struct socket *sock, struct sockaddr *myaddr,
ask = alg_sk(sock->sk);
DUMP_ASK(ask);
- // FIXME: locking
-
- if (ask_op_type(ask) != OP_NONE)
- return -EINVAL;
+ mutex_lock(&ask->mutex);
+ if (ask_op_type(ask) != OP_NONE) {
+ res = -EINVAL;
+ goto out_unlock;
+ }
if (strncmp(addr->salg_type, "hash", sizeof(addr->salg_type)) == 0) {
BUG_ON(ask->hash.init != 0);
res = cryptodev_hash_init(&ask->hash, addr->salg_tfm, NULL, 0);
if (res != 0)
- return res;
+ goto out_unlock;
atomic_set(&ask->op_type, OP_HASH);
- } else
- return -EINVAL;
+ } else {
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ res = 0;
+out_unlock:
+ mutex_unlock(&ask->mutex);
DUMP_ASK(ask);
- return 0;
+ return res;
}
static int alg_accept(struct socket *sock, struct socket *newsock, int flags)
@@ -549,14 +560,18 @@ static int alg_accept(struct socket *sock, struct socket *newsock, int flags)
struct alg_sock *ask;
struct data_sock *dsk;
- // FIXME: locking
ask = alg_sk(sock->sk);
DUMP_ASK(ask);
- if (ask->accept_idx >= ask->num_slaves)
- return -EINVAL;
+ mutex_lock(&ask->mutex);
+ if (ask->accept_idx >= ask->num_slaves) {
+ mutex_unlock(&ask->mutex);
+ return -EINVAL;
+ }
dsk = ask->slaves[ask->accept_idx];
ask->accept_idx++;
+ mutex_unlock(&ask->mutex);
+
DUMP_DSK(dsk);
DUMP_ASK(ask);
@@ -579,14 +594,11 @@ static int alg_listen(struct socket *sock, int len)
struct alg_sock *ask;
struct data_sock *dsk;
size_t i;
+ int res;
- // FIXME: locking
ask = alg_sk(sock->sk);
DUMP_ASK(ask);
- if (ask->num_slaves != 0)
- return -EINVAL;
-
switch (ask_op_type(ask)) {
case OP_NONE:
return -EDESTADDRREQ;
@@ -599,9 +611,15 @@ static int alg_listen(struct socket *sock, int len)
default:
BUG();
}
-
BUG_ON(len > ARRAY_SIZE(ask->slaves));
+ mutex_lock(&ask->mutex);
+
+ if (ask->num_slaves != 0) {
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
net = sock_net(sock->sk);
for (i = 0; i < len; i++) {
struct sock *newsk;
@@ -625,9 +643,12 @@ static int alg_listen(struct socket *sock, int len)
}
ask->num_slaves = len;
- DUMP_ASK(ask);
+ res = 0;
- return 0;
+out_unlock:
+ mutex_unlock(&ask->mutex);
+ DUMP_ASK(ask);
+ return res;
err_partial:
while (i != 0) {
@@ -641,8 +662,8 @@ err_partial:
sock_put(&dsk->sk);
DUMP_DSK(dsk);
}
- DUMP_ASK(ask);
- return -ENOMEM;
+ res = -ENOMEM;
+ goto out_unlock;
}
static int alg_sendmsg(struct kiocb *iocb, struct socket *sock,
@@ -702,6 +723,7 @@ static int alg_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
+ struct alg_sock *ask;
if (sock->type != SOCK_STREAM)
return -ESOCKTNOSUPPORT;
@@ -715,6 +737,8 @@ static int alg_create(struct net *net, struct socket *sock, int protocol,
return -ENOMEM;
sock_init_data(sock, sk);
+ ask = alg_sk(sk);
+ mutex_init(&ask->mutex);
local_bh_disable();
sock_prot_inuse_add(net, &alg_proto, 1);