diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-05-01 15:15:44 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-05-10 03:28:53 -0400 |
commit | 6161c0382bbab883a634d284f7367a88bbe88534 (patch) | |
tree | 86b4de3160054b0507d37a47351260e48073f579 /net/bluetooth/l2cap.c | |
parent | 1890d36bb556a27684ad29654a9898ab9a5f57ee (diff) |
Bluetooth: Add wait_queue to wait ack of all sent packets
To guarantee that all packets we sent were received we need to wait for
theirs ack before shutdown the socket.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 103e4b54a86a..9d514f9dbc0f 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -1242,6 +1242,37 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l | |||
1242 | return 0; | 1242 | return 0; |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | static int __l2cap_wait_ack(struct sock *sk) | ||
1246 | { | ||
1247 | DECLARE_WAITQUEUE(wait, current); | ||
1248 | int err = 0; | ||
1249 | int timeo = HZ/5; | ||
1250 | |||
1251 | add_wait_queue(sk->sk_sleep, &wait); | ||
1252 | while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { | ||
1253 | set_current_state(TASK_INTERRUPTIBLE); | ||
1254 | |||
1255 | if (!timeo) | ||
1256 | timeo = HZ/5; | ||
1257 | |||
1258 | if (signal_pending(current)) { | ||
1259 | err = sock_intr_errno(timeo); | ||
1260 | break; | ||
1261 | } | ||
1262 | |||
1263 | release_sock(sk); | ||
1264 | timeo = schedule_timeout(timeo); | ||
1265 | lock_sock(sk); | ||
1266 | |||
1267 | err = sock_error(sk); | ||
1268 | if (err) | ||
1269 | break; | ||
1270 | } | ||
1271 | set_current_state(TASK_RUNNING); | ||
1272 | remove_wait_queue(sk->sk_sleep, &wait); | ||
1273 | return err; | ||
1274 | } | ||
1275 | |||
1245 | static void l2cap_monitor_timeout(unsigned long arg) | 1276 | static void l2cap_monitor_timeout(unsigned long arg) |
1246 | { | 1277 | { |
1247 | struct sock *sk = (void *) arg; | 1278 | struct sock *sk = (void *) arg; |
@@ -2059,6 +2090,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) | |||
2059 | 2090 | ||
2060 | lock_sock(sk); | 2091 | lock_sock(sk); |
2061 | if (!sk->sk_shutdown) { | 2092 | if (!sk->sk_shutdown) { |
2093 | if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) | ||
2094 | err = __l2cap_wait_ack(sk); | ||
2095 | |||
2062 | sk->sk_shutdown = SHUTDOWN_MASK; | 2096 | sk->sk_shutdown = SHUTDOWN_MASK; |
2063 | l2cap_sock_clear_timer(sk); | 2097 | l2cap_sock_clear_timer(sk); |
2064 | __l2cap_sock_close(sk, 0); | 2098 | __l2cap_sock_close(sk, 0); |