aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_sock.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--net/bluetooth/hci_sock.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index d0dad1fafe07..06581223238c 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -869,7 +869,8 @@ static int hci_sock_release(struct socket *sock)
hdev = hci_pi(sk)->hdev;
if (hdev) {
- if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
+ if (hci_pi(sk)->channel == HCI_CHANNEL_USER &&
+ !hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
/* When releasing a user channel exclusive access,
* call hci_dev_do_close directly instead of calling
* hci_dev_close to ensure the exclusive access will
@@ -878,6 +879,11 @@ static int hci_sock_release(struct socket *sock)
* The checking of HCI_AUTO_OFF is not needed in this
* case since it will have been cleared already when
* opening the user channel.
+ *
+ * Make sure to also check that we haven't already
+ * unregistered since all the cleanup will have already
+ * been complete and hdev will get released when we put
+ * below.
*/
hci_dev_do_close(hdev);
hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
@@ -889,10 +895,6 @@ static int hci_sock_release(struct socket *sock)
}
sock_orphan(sk);
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-
release_sock(sk);
sock_put(sk);
return 0;
@@ -1457,7 +1459,6 @@ static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t len, int flags)
{
- int noblock = flags & MSG_DONTWAIT;
struct sock *sk = sock->sk;
struct sk_buff *skb;
int copied, err;
@@ -1474,7 +1475,7 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
if (sk->sk_state == BT_CLOSED)
return 0;
- skb = skb_recv_datagram(sk, flags, noblock, &err);
+ skb = skb_recv_datagram(sk, flags, &err);
if (!skb)
return err;
@@ -1915,7 +1916,8 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
{
struct sock *sk = sock->sk;
- int err = 0, opt = 0;
+ int err = 0;
+ u16 opt;
BT_DBG("sk %p, opt %d", sk, optname);
@@ -1941,7 +1943,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
goto done;
}
- if (copy_from_sockptr(&opt, optval, sizeof(u16))) {
+ if (copy_from_sockptr(&opt, optval, sizeof(opt))) {
err = -EFAULT;
break;
}
@@ -2058,6 +2060,13 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
return err;
}
+static void hci_sock_destruct(struct sock *sk)
+{
+ mgmt_cleanup(sk);
+ skb_queue_purge(&sk->sk_receive_queue);
+ skb_queue_purge(&sk->sk_write_queue);
+}
+
static const struct proto_ops hci_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
@@ -2111,6 +2120,7 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
sock->state = SS_UNCONNECTED;
sk->sk_state = BT_OPEN;
+ sk->sk_destruct = hci_sock_destruct;
bt_sock_link(&hci_sk_list, sk);
return 0;