Bluetooth: L2CAP: add support for waiting disconnection resp
Whenever we disconnect a L2CAP connection, we would immediately report a disconnection event (EPOLLHUP) to the upper layer, without waiting for the response of the other device. This patch offers an option to wait until we receive a disconnection response before reporting disconnection event, by using the "how" parameter in l2cap_sock_shutdown(). Therefore, upper layer can opt to wait for disconnection response by shutdown(sock, SHUT_WR). This can be used to enforce proper disconnection order in HID, where the disconnection of the interrupt channel must be complete before attempting to disconnect the control channel. Signed-off-by: Archie Pusaka <apusaka@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Родитель
adf1d69264
Коммит
5b440676c1
|
@ -1271,14 +1271,21 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|||
struct l2cap_conn *conn;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
BT_DBG("sock %p, sk %p, how %d", sock, sk, how);
|
||||
|
||||
/* 'how' parameter is mapped to sk_shutdown as follows:
|
||||
* SHUT_RD (0) --> RCV_SHUTDOWN (1)
|
||||
* SHUT_WR (1) --> SEND_SHUTDOWN (2)
|
||||
* SHUT_RDWR (2) --> SHUTDOWN_MASK (3)
|
||||
*/
|
||||
how++;
|
||||
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_shutdown)
|
||||
if ((sk->sk_shutdown & how) == how)
|
||||
goto shutdown_already;
|
||||
|
||||
BT_DBG("Handling sock shutdown");
|
||||
|
@ -1301,11 +1308,20 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|||
* has already been actioned to close the L2CAP
|
||||
* link such as by l2cap_disconnection_req().
|
||||
*/
|
||||
if (sk->sk_shutdown)
|
||||
goto has_shutdown;
|
||||
if ((sk->sk_shutdown & how) == how)
|
||||
goto shutdown_matched;
|
||||
}
|
||||
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
/* Try setting the RCV_SHUTDOWN bit, return early if SEND_SHUTDOWN
|
||||
* is already set
|
||||
*/
|
||||
if ((how & RCV_SHUTDOWN) && !(sk->sk_shutdown & RCV_SHUTDOWN)) {
|
||||
sk->sk_shutdown |= RCV_SHUTDOWN;
|
||||
if ((sk->sk_shutdown & how) == how)
|
||||
goto shutdown_matched;
|
||||
}
|
||||
|
||||
sk->sk_shutdown |= SEND_SHUTDOWN;
|
||||
release_sock(sk);
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
|
@ -1335,7 +1351,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|||
err = bt_sock_wait_state(sk, BT_CLOSED,
|
||||
sk->sk_lingertime);
|
||||
|
||||
has_shutdown:
|
||||
shutdown_matched:
|
||||
l2cap_chan_put(chan);
|
||||
sock_put(sk);
|
||||
|
||||
|
@ -1363,7 +1379,7 @@ static int l2cap_sock_release(struct socket *sock)
|
|||
|
||||
bt_sock_unlink(&l2cap_sk_list, sk);
|
||||
|
||||
err = l2cap_sock_shutdown(sock, 2);
|
||||
err = l2cap_sock_shutdown(sock, SHUT_RDWR);
|
||||
chan = l2cap_pi(sk)->chan;
|
||||
|
||||
l2cap_chan_hold(chan);
|
||||
|
|
Загрузка…
Ссылка в новой задаче