Commit 40c75f81 authored by Samuel Ortiz's avatar Samuel Ortiz Committed by John W. Linville

NFC: Fix LLCP sockets releasing path

The socket local pointer needs to be set to NULL when the adapter is
removed or the MAC goes down.
If the socket release code is called after such an event, the socket
reference count still needs to be decreased in order for the socket to
eventually be freed.
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 47807d3d
...@@ -47,7 +47,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) ...@@ -47,7 +47,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
/* Release all child sockets */ /* Release all child sockets */
list_for_each_entry_safe(s, n, &parent->list, list) { list_for_each_entry_safe(s, n, &parent->list, list) {
list_del(&s->list); list_del_init(&s->list);
sk = &s->sk; sk = &s->sk;
lock_sock(sk); lock_sock(sk);
...@@ -56,9 +56,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) ...@@ -56,9 +56,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
nfc_put_device(s->dev); nfc_put_device(s->dev);
sk->sk_state = LLCP_CLOSED; sk->sk_state = LLCP_CLOSED;
sock_set_flag(sk, SOCK_DEAD);
release_sock(sk); release_sock(sk);
sock_orphan(sk);
s->local = NULL;
} }
parent_sk = &parent->sk; parent_sk = &parent->sk;
...@@ -77,11 +80,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) ...@@ -77,11 +80,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
nfc_llcp_accept_unlink(accept_sk); nfc_llcp_accept_unlink(accept_sk);
accept_sk->sk_state = LLCP_CLOSED; accept_sk->sk_state = LLCP_CLOSED;
sock_set_flag(accept_sk, SOCK_DEAD);
release_sock(accept_sk); release_sock(accept_sk);
sock_orphan(accept_sk); sock_orphan(accept_sk);
lsk->local = NULL;
} }
} }
...@@ -89,9 +93,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) ...@@ -89,9 +93,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
nfc_put_device(parent->dev); nfc_put_device(parent->dev);
parent_sk->sk_state = LLCP_CLOSED; parent_sk->sk_state = LLCP_CLOSED;
sock_set_flag(parent_sk, SOCK_DEAD);
release_sock(parent_sk); release_sock(parent_sk);
sock_orphan(parent_sk);
parent->local = NULL;
} }
mutex_unlock(&local->socket_lock); mutex_unlock(&local->socket_lock);
......
...@@ -315,6 +315,7 @@ static int llcp_sock_release(struct socket *sock) ...@@ -315,6 +315,7 @@ static int llcp_sock_release(struct socket *sock)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct nfc_llcp_local *local; struct nfc_llcp_local *local;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
int err = 0;
if (!sk) if (!sk)
return 0; return 0;
...@@ -322,15 +323,17 @@ static int llcp_sock_release(struct socket *sock) ...@@ -322,15 +323,17 @@ static int llcp_sock_release(struct socket *sock)
pr_debug("%p\n", sk); pr_debug("%p\n", sk);
local = llcp_sock->local; local = llcp_sock->local;
if (local == NULL) if (local == NULL) {
return -ENODEV; err = -ENODEV;
goto out;
}
mutex_lock(&local->socket_lock); mutex_lock(&local->socket_lock);
if (llcp_sock == local->sockets[llcp_sock->ssap]) if (llcp_sock == local->sockets[llcp_sock->ssap])
local->sockets[llcp_sock->ssap] = NULL; local->sockets[llcp_sock->ssap] = NULL;
else else
list_del(&llcp_sock->list); list_del_init(&llcp_sock->list);
mutex_unlock(&local->socket_lock); mutex_unlock(&local->socket_lock);
...@@ -354,9 +357,7 @@ static int llcp_sock_release(struct socket *sock) ...@@ -354,9 +357,7 @@ static int llcp_sock_release(struct socket *sock)
release_sock(accept_sk); release_sock(accept_sk);
sock_set_flag(sk, SOCK_DEAD);
sock_orphan(accept_sk); sock_orphan(accept_sk);
sock_put(accept_sk);
} }
} }
...@@ -367,14 +368,13 @@ static int llcp_sock_release(struct socket *sock) ...@@ -367,14 +368,13 @@ static int llcp_sock_release(struct socket *sock)
sk->sk_state == LLCP_LISTEN) sk->sk_state == LLCP_LISTEN)
nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
sock_set_flag(sk, SOCK_DEAD);
release_sock(sk); release_sock(sk);
out:
sock_orphan(sk); sock_orphan(sk);
sock_put(sk); sock_put(sk);
return 0; return err;
} }
static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
...@@ -645,6 +645,8 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) ...@@ -645,6 +645,8 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
void nfc_llcp_sock_free(struct nfc_llcp_sock *sock) void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
{ {
struct nfc_llcp_local *local = sock->local;
kfree(sock->service_name); kfree(sock->service_name);
skb_queue_purge(&sock->tx_queue); skb_queue_purge(&sock->tx_queue);
...@@ -653,6 +655,11 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock) ...@@ -653,6 +655,11 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
list_del_init(&sock->accept_queue); list_del_init(&sock->accept_queue);
if (local != NULL && sock == local->sockets[sock->ssap])
local->sockets[sock->ssap] = NULL;
else
list_del_init(&sock->list);
sock->parent = NULL; sock->parent = NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment