};
/* ---- ISO connections ---- */
+enum {
+ ISO_CONN_DROPPED,
+ __ISO_CONN_NUM_FLAGS
+};
+
struct iso_conn {
struct hci_conn *hcon;
+ DECLARE_BITMAP(flags, __ISO_CONN_NUM_FLAGS);
/* @lock: spinlock protecting changes to iso_conn fields */
spinlock_t lock;
if (conn->hcon) {
conn->hcon->iso_data = NULL;
- hci_conn_drop(conn->hcon);
+ if (!test_and_set_bit(ISO_CONN_DROPPED, conn->flags))
+ hci_conn_drop(conn->hcon);
}
/* Ensure no more work items will run since hci_conn has been dropped */
iso_pi(sk)->conn = conn;
conn->sk = sk;
+ clear_bit(ISO_CONN_DROPPED, conn->flags);
if (parent)
bt_accept_enqueue(parent, sk, true);
}
sk->sk_state = BT_DISCONN;
- iso_conn_lock(iso_pi(sk)->conn);
- hci_conn_drop(iso_pi(sk)->conn->hcon);
- iso_pi(sk)->conn->hcon->iso_data = NULL;
- iso_pi(sk)->conn->hcon = NULL;
- iso_conn_unlock(iso_pi(sk)->conn);
+ if (!test_and_set_bit(ISO_CONN_DROPPED, iso_pi(sk)->conn->flags))
+ hci_conn_drop(iso_pi(sk)->conn->hcon);
}
static void __iso_sock_close(struct sock *sk)
return;
lock_sock(sk);
+
+ switch (sk->sk_state) {
+ case BT_DISCONN:
+ case BT_CLOSED:
+ release_sock(sk);
+ return;
+ }
+
iso_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
+
release_sock(sk);
}