summaryrefslogtreecommitdiff
path: root/net/bluetooth/iso.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/iso.c')
-rw-r--r--net/bluetooth/iso.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 7cb2864fe872..876649556d3c 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -564,7 +564,7 @@ static void iso_recv_frame(struct iso_conn *conn, struct sk_buff *skb)
struct sock *sk;
iso_conn_lock(conn);
- sk = conn->sk;
+ sk = iso_sock_hold(conn);
iso_conn_unlock(conn);
if (!sk)
@@ -573,11 +573,15 @@ static void iso_recv_frame(struct iso_conn *conn, struct sk_buff *skb)
BT_DBG("sk %p len %d", sk, skb->len);
if (sk->sk_state != BT_CONNECTED)
- goto drop;
+ goto drop_put;
- if (!sock_queue_rcv_skb(sk, skb))
+ if (!sock_queue_rcv_skb(sk, skb)) {
+ sock_put(sk);
return;
+ }
+drop_put:
+ sock_put(sk);
drop:
kfree_skb(skb);
}
@@ -751,6 +755,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)
while ((sk = bt_accept_dequeue(parent, NULL))) {
iso_sock_close(sk);
iso_sock_kill(sk);
+ /* Drop the reference handed back by bt_accept_dequeue(). */
+ sock_put(sk);
}
/* If listening socket has a hcon, properly disconnect it */
@@ -858,8 +864,8 @@ static void __iso_sock_close(struct sock *sk)
/* Must be called on unlocked socket. */
static void iso_sock_close(struct sock *sk)
{
- iso_sock_clear_timer(sk);
lock_sock(sk);
+ iso_sock_clear_timer(sk);
__iso_sock_close(sk);
release_sock(sk);
iso_sock_kill(sk);
@@ -1356,8 +1362,13 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock,
}
ch = bt_accept_dequeue(sk, newsock);
- if (ch)
+ if (ch) {
+ /* Drop the bridging ref from bt_accept_dequeue();
+ * the grafted socket keeps ch alive from here.
+ */
+ sock_put(ch);
break;
+ }
if (!timeo) {
err = -EAGAIN;
@@ -2593,6 +2604,11 @@ int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb, u16 flags)
break;
case ISO_END:
+ if (!conn->rx_len) {
+ BT_ERR("Unexpected end frame (len %d)", skb->len);
+ goto drop;
+ }
+
skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
skb->len);
conn->rx_len -= skb->len;