spinlock_t lock;
struct sock *sk;
- struct delayed_work timeout_work;
-
struct sk_buff *rx_skb;
__u32 rx_len;
__u16 tx_sn;
__u8 base_len;
__u8 base[BASE_MAX_LENGTH];
struct iso_conn *conn;
+ struct delayed_work timeout_work;
};
static struct bt_iso_qos default_qos;
hci_conn_drop(conn->hcon);
}
- /* Ensure no more work items will run since hci_conn has been dropped */
- disable_delayed_work_sync(&conn->timeout_work);
-
kfree_skb(conn->rx_skb);
kfree(conn);
static void iso_sock_timeout(struct work_struct *work)
{
- struct iso_conn *conn = container_of(work, struct iso_conn,
- timeout_work.work);
- struct sock *sk;
-
- conn = iso_conn_hold_unless_zero(conn);
- if (!conn)
- return;
-
- iso_conn_lock(conn);
- sk = iso_sock_hold(conn);
- iso_conn_unlock(conn);
- iso_conn_put(conn);
-
- if (!sk)
- return;
+ struct iso_pinfo *pi = container_of(work, struct iso_pinfo,
+ timeout_work.work);
+ struct sock *sk = &pi->bt.sk;
BT_DBG("sock %p state %d", sk, sk->sk_state);
lock_sock(sk);
- sk->sk_err = ETIMEDOUT;
- sk->sk_state_change(sk);
+ if (!sock_flag(sk, SOCK_ZAPPED)) {
+ sk->sk_err = ETIMEDOUT;
+ sk->sk_state_change(sk);
+ }
release_sock(sk);
- sock_put(sk);
}
static void iso_sock_set_timer(struct sock *sk, long timeout)
{
+ lockdep_assert(lockdep_sock_is_held(sk));
+
+ cancel_delayed_work(&iso_pi(sk)->timeout_work);
+
if (!iso_pi(sk)->conn)
return;
BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
- cancel_delayed_work(&iso_pi(sk)->conn->timeout_work);
- schedule_delayed_work(&iso_pi(sk)->conn->timeout_work, timeout);
+ schedule_delayed_work(&iso_pi(sk)->timeout_work, timeout);
}
static void iso_sock_clear_timer(struct sock *sk)
{
- if (!iso_pi(sk)->conn)
- return;
+ BT_DBG("sock %p state %d", sk, sk->sk_state);
+ cancel_delayed_work(&iso_pi(sk)->timeout_work);
+}
+
+static void iso_sock_disable_timer(struct sock *sk)
+{
+ lockdep_assert(!lockdep_sock_is_held(sk));
BT_DBG("sock %p state %d", sk, sk->sk_state);
- cancel_delayed_work(&iso_pi(sk)->conn->timeout_work);
+ disable_delayed_work_sync(&iso_pi(sk)->timeout_work);
}
/* ---- ISO connections ---- */
kref_init(&conn->ref);
spin_lock_init(&conn->lock);
- INIT_DELAYED_WORK(&conn->timeout_work, iso_sock_timeout);
hcon->iso_data = conn;
conn->hcon = hcon;
return;
}
+ iso_sock_disable_timer(sk);
+
lock_sock(sk);
- iso_sock_clear_timer(sk);
iso_chan_del(sk, err);
release_sock(sk);
iso_sock_kill(sk);
*/
static void iso_sock_kill(struct sock *sk)
{
+ iso_sock_disable_timer(sk);
+
lock_sock(sk);
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket ||
/* Must be called on unlocked socket. */
static void iso_sock_close(struct sock *sk)
{
+ iso_sock_disable_timer(sk);
+
lock_sock(sk);
- iso_sock_clear_timer(sk);
__iso_sock_close(sk);
release_sock(sk);
}
iso_pi(sk)->qos = default_qos;
iso_pi(sk)->sync_handle = -1;
+ INIT_DELAYED_WORK(&iso_pi(sk)->timeout_work, iso_sock_timeout);
+
bt_sock_link(&iso_sk_list, sk);
return sk;
}