Bluetooth: Hold socket in defer callback in L2CAP socket
In both places that we use the defer callback the socket lock is held for a indirect sk access inside __l2cap_change_state() and chan->ops->defer(), all the rest of the code between lock_sock() and release_sock() is already protected by the channel lock and won't be affected by this change. We now use l2cap_change_state(), the locked version of the change state function, and the defer callback does the locking itself now. This does not affect other uses of the defer callback. Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
0f2c615374
commit
acdcabf532
|
@ -1299,20 +1299,16 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||||
rsp.dcid = cpu_to_le16(chan->scid);
|
rsp.dcid = cpu_to_le16(chan->scid);
|
||||||
|
|
||||||
if (l2cap_chan_check_security(chan)) {
|
if (l2cap_chan_check_security(chan)) {
|
||||||
struct sock *sk = chan->sk;
|
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
|
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
|
||||||
rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
|
rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
|
||||||
rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
|
rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
|
||||||
chan->ops->defer(chan);
|
chan->ops->defer(chan);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
__l2cap_state_change(chan, BT_CONFIG);
|
l2cap_state_change(chan, BT_CONFIG);
|
||||||
rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
|
rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
|
||||||
rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
|
rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||||
}
|
}
|
||||||
release_sock(sk);
|
|
||||||
} else {
|
} else {
|
||||||
rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
|
rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
|
||||||
rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
|
rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
|
||||||
|
@ -6643,31 +6639,26 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
||||||
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
||||||
}
|
}
|
||||||
} else if (chan->state == BT_CONNECT2) {
|
} else if (chan->state == BT_CONNECT2) {
|
||||||
struct sock *sk = chan->sk;
|
|
||||||
struct l2cap_conn_rsp rsp;
|
struct l2cap_conn_rsp rsp;
|
||||||
__u16 res, stat;
|
__u16 res, stat;
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
|
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
|
||||||
res = L2CAP_CR_PEND;
|
res = L2CAP_CR_PEND;
|
||||||
stat = L2CAP_CS_AUTHOR_PEND;
|
stat = L2CAP_CS_AUTHOR_PEND;
|
||||||
chan->ops->defer(chan);
|
chan->ops->defer(chan);
|
||||||
} else {
|
} else {
|
||||||
__l2cap_state_change(chan, BT_CONFIG);
|
l2cap_state_change(chan, BT_CONFIG);
|
||||||
res = L2CAP_CR_SUCCESS;
|
res = L2CAP_CR_SUCCESS;
|
||||||
stat = L2CAP_CS_NO_INFO;
|
stat = L2CAP_CS_NO_INFO;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
__l2cap_state_change(chan, BT_DISCONN);
|
l2cap_state_change(chan, BT_DISCONN);
|
||||||
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
||||||
res = L2CAP_CR_SEC_BLOCK;
|
res = L2CAP_CR_SEC_BLOCK;
|
||||||
stat = L2CAP_CS_NO_INFO;
|
stat = L2CAP_CS_NO_INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
release_sock(sk);
|
|
||||||
|
|
||||||
rsp.scid = cpu_to_le16(chan->dcid);
|
rsp.scid = cpu_to_le16(chan->dcid);
|
||||||
rsp.dcid = cpu_to_le16(chan->scid);
|
rsp.dcid = cpu_to_le16(chan->scid);
|
||||||
rsp.result = cpu_to_le16(res);
|
rsp.result = cpu_to_le16(res);
|
||||||
|
|
|
@ -1195,11 +1195,15 @@ static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
|
||||||
|
|
||||||
static void l2cap_sock_defer_cb(struct l2cap_chan *chan)
|
static void l2cap_sock_defer_cb(struct l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
struct sock *sk = chan->data;
|
struct sock *parent, *sk = chan->data;
|
||||||
struct sock *parent = bt_sk(sk)->parent;
|
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
|
||||||
|
parent = bt_sk(sk)->parent;
|
||||||
if (parent)
|
if (parent)
|
||||||
parent->sk_data_ready(parent, 0);
|
parent->sk_data_ready(parent, 0);
|
||||||
|
|
||||||
|
release_sock(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
|
static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
|
||||||
|
|
Loading…
Reference in New Issue