Bluetooth: invert locking order in connect path
This move some checking code that was in l2cap_sock_connect() to l2cap_chan_connect(). Thus we can invert the lock calls, i.e., call lock_sock() before hci_dev_lock() to avoid a deadlock scenario. Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
This commit is contained in:
parent
f878fcad17
commit
03a0019481
3 changed files with 61 additions and 61 deletions
|
@ -806,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
|
|||
struct l2cap_chan *l2cap_chan_create(struct sock *sk);
|
||||
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
|
||||
void l2cap_chan_destroy(struct l2cap_chan *chan);
|
||||
int l2cap_chan_connect(struct l2cap_chan *chan);
|
||||
inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
bdaddr_t *dst);
|
||||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
u32 priority);
|
||||
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
|
||||
|
|
|
@ -1144,11 +1144,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
|
|||
return c1;
|
||||
}
|
||||
|
||||
int l2cap_chan_connect(struct l2cap_chan *chan)
|
||||
inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
|
||||
{
|
||||
struct sock *sk = chan->sk;
|
||||
bdaddr_t *src = &bt_sk(sk)->src;
|
||||
bdaddr_t *dst = &bt_sk(sk)->dst;
|
||||
struct l2cap_conn *conn;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
|
@ -1164,6 +1163,61 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
|
|||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
/* PSM must be odd and lsb of upper byte must be 0 */
|
||||
if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
|
||||
chan->chan_type != L2CAP_CHAN_RAW) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
break;
|
||||
case L2CAP_MODE_ERTM:
|
||||
case L2CAP_MODE_STREAMING:
|
||||
if (!disable_ertm)
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
err = -ENOTSUPP;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (sk->sk_state) {
|
||||
case BT_CONNECT:
|
||||
case BT_CONNECT2:
|
||||
case BT_CONFIG:
|
||||
/* Already connecting */
|
||||
err = 0;
|
||||
goto done;
|
||||
|
||||
case BT_CONNECTED:
|
||||
/* Already connected */
|
||||
err = -EISCONN;
|
||||
goto done;
|
||||
|
||||
case BT_OPEN:
|
||||
case BT_BOUND:
|
||||
/* Can connect */
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EBADFD;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set destination address and psm */
|
||||
bacpy(&bt_sk(sk)->dst, src);
|
||||
chan->psm = psm;
|
||||
chan->dcid = cid;
|
||||
|
||||
auth_type = l2cap_get_auth_type(chan);
|
||||
|
||||
if (chan->dcid == L2CAP_CID_LE_DATA)
|
||||
|
|
|
@ -121,70 +121,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
|
|||
if (la.l2_cid && la.l2_psm)
|
||||
return -EINVAL;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED
|
||||
&& !(la.l2_psm || la.l2_cid)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
break;
|
||||
case L2CAP_MODE_ERTM:
|
||||
case L2CAP_MODE_STREAMING:
|
||||
if (!disable_ertm)
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
err = -ENOTSUPP;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (sk->sk_state) {
|
||||
case BT_CONNECT:
|
||||
case BT_CONNECT2:
|
||||
case BT_CONFIG:
|
||||
/* Already connecting */
|
||||
goto wait;
|
||||
|
||||
case BT_CONNECTED:
|
||||
/* Already connected */
|
||||
err = -EISCONN;
|
||||
goto done;
|
||||
|
||||
case BT_OPEN:
|
||||
case BT_BOUND:
|
||||
/* Can connect */
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EBADFD;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* PSM must be odd and lsb of upper byte must be 0 */
|
||||
if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !la.l2_cid &&
|
||||
chan->chan_type != L2CAP_CHAN_RAW) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set destination address and psm */
|
||||
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
|
||||
chan->psm = la.l2_psm;
|
||||
chan->dcid = la.l2_cid;
|
||||
|
||||
err = l2cap_chan_connect(chan);
|
||||
err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
wait:
|
||||
err = bt_sock_wait_state(sk, BT_CONNECTED,
|
||||
sock_sndtimeo(sk, flags & O_NONBLOCK));
|
||||
done:
|
||||
release_sock(sk);
|
||||
if (sock_owned_by_user(sk))
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue