diff options
author | Dean Jenkins <Dean_Jenkins@mentor.com> | 2015-10-14 06:18:47 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-10-20 18:49:26 -0400 |
commit | 9f7378a9d6ced1784e08d3e21a9ddb769523baf2 (patch) | |
tree | 500bf645b5dd1c47fc829697ec58a8e40f57a8c0 /net/bluetooth/l2cap_sock.c | |
parent | 04ba72e6b24f1e0e2221fcd73f08782870473fa1 (diff) |
Bluetooth: l2cap_disconnection_req priority over shutdown
There is a L2CAP protocol race between the local peer and
the remote peer demanding disconnection of the L2CAP link.
When L2CAP ERTM is used, l2cap_sock_shutdown() can be called
from userland to disconnect L2CAP. However, there can be a
delay introduced by waiting for ACKs. During this waiting
period, the remote peer may have sent a Disconnection Request.
Therefore, recheck the shutdown status of the socket
after waiting for ACKs because there is no need to do
further processing if the connection has gone.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Signed-off-by: Harish Jenny K N <harish_kandiga@mentor.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d06fb54082aa..1bb551527044 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -1129,9 +1129,17 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) | |||
1129 | 1129 | ||
1130 | if (chan->mode == L2CAP_MODE_ERTM && | 1130 | if (chan->mode == L2CAP_MODE_ERTM && |
1131 | chan->unacked_frames > 0 && | 1131 | chan->unacked_frames > 0 && |
1132 | chan->state == BT_CONNECTED) | 1132 | chan->state == BT_CONNECTED) { |
1133 | err = __l2cap_wait_ack(sk, chan); | 1133 | err = __l2cap_wait_ack(sk, chan); |
1134 | 1134 | ||
1135 | /* After waiting for ACKs, check whether shutdown | ||
1136 | * has already been actioned to close the L2CAP | ||
1137 | * link such as by l2cap_disconnection_req(). | ||
1138 | */ | ||
1139 | if (sk->sk_shutdown) | ||
1140 | goto has_shutdown; | ||
1141 | } | ||
1142 | |||
1135 | sk->sk_shutdown = SHUTDOWN_MASK; | 1143 | sk->sk_shutdown = SHUTDOWN_MASK; |
1136 | release_sock(sk); | 1144 | release_sock(sk); |
1137 | 1145 | ||
@@ -1162,6 +1170,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) | |||
1162 | err = bt_sock_wait_state(sk, BT_CLOSED, | 1170 | err = bt_sock_wait_state(sk, BT_CLOSED, |
1163 | sk->sk_lingertime); | 1171 | sk->sk_lingertime); |
1164 | 1172 | ||
1173 | has_shutdown: | ||
1165 | l2cap_chan_put(chan); | 1174 | l2cap_chan_put(chan); |
1166 | sock_put(sk); | 1175 | sock_put(sk); |
1167 | 1176 | ||