Commit 556e841e authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Fix race when unlinking incoming connections

When the user space applications don't call accept() it can happen that
incoming connections stay in the accept queue and block further connection
attempts until the server is restarted. On a disconnect it is necessary
that the connection is removed from the accept queue. This can't be the
job of a cleanup function.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 782de66e
......@@ -133,6 +133,7 @@ uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
void bt_accept_enqueue(struct sock *parent, struct sock *sk);
void bt_accept_unlink(struct sock *sk);
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
/* Skb helpers */
......
......@@ -165,7 +165,7 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk)
}
EXPORT_SYMBOL(bt_accept_enqueue);
static void bt_accept_unlink(struct sock *sk)
void bt_accept_unlink(struct sock *sk)
{
BT_DBG("sk %p state %d", sk, sk->sk_state);
......@@ -174,6 +174,7 @@ static void bt_accept_unlink(struct sock *sk)
bt_sk(sk)->parent = NULL;
sock_put(sk);
}
EXPORT_SYMBOL(bt_accept_unlink);
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
{
......@@ -186,6 +187,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
lock_sock(sk);
/* FIXME: Is this check still needed */
if (sk->sk_state == BT_CLOSED) {
release_sock(sk);
bt_accept_unlink(sk);
......@@ -199,6 +202,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
release_sock(sk);
return sk;
}
release_sock(sk);
}
return NULL;
......
......@@ -1005,9 +1005,10 @@ static void l2cap_chan_del(struct sock *sk, int err)
if (err)
sk->sk_err = err;
if (parent)
if (parent) {
bt_accept_unlink(sk);
parent->sk_data_ready(parent, 0);
else
} else
sk->sk_state_change(sk);
}
......@@ -1303,7 +1304,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
if (pi->imtu != L2CAP_DEFAULT_MTU)
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
/* FIXME. Need actual value of the flush timeout */
/* FIXME: Need actual value of the flush timeout */
//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
// l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
......
......@@ -97,17 +97,26 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
if (err)
sk->sk_err = err;
sk->sk_state = d->state;
parent = bt_sk(sk)->parent;
if (!parent) {
if (parent) {
if (d->state == BT_CLOSED) {
sk->sk_zapped = 1;
bt_accept_unlink(sk);
}
parent->sk_data_ready(parent, 0);
} else {
if (d->state == BT_CONNECTED)
rfcomm_session_getaddr(d->session, &bt_sk(sk)->src, NULL);
sk->sk_state_change(sk);
} else
parent->sk_data_ready(parent, 0);
}
bh_unlock_sock(sk);
if (parent && sk->sk_zapped)
rfcomm_sock_kill(sk);
}
/* ---- Socket functions ---- */
......
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