diff options
author | Gustavo F. Padovan <gustavo@las.ic.unicamp.br> | 2009-08-20 21:26:00 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-22 17:56:15 -0400 |
commit | e90bac061b17cd81bd0df30606c64f4543bf5ca0 (patch) | |
tree | 3529111fa5ba07bdd8ed9627d10d623f77416ace /net/bluetooth | |
parent | 30afb5b2aa83adf4f69e5090d48e1bb04b64c58a (diff) |
Bluetooth: Add support for Retransmission and Monitor Timers
L2CAP uses retransmission and monitor timers to inquiry the other side
about unacked I-frames. After sending each I-frame we (re)start the
retransmission timer. If it expires, we start a monitor timer that send a
S-frame with P bit set and wait for S-frame with F bit set. If monitor
timer expires, try again, at a maximum of L2CAP_DEFAULT_MAX_TX.
Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/l2cap.c | 86 |
1 files changed, 82 insertions, 4 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 35e9f5b80545..97172f7c0a6a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -1178,6 +1178,39 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l | |||
1178 | return 0; | 1178 | return 0; |
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | static void l2cap_monitor_timeout(unsigned long arg) | ||
1182 | { | ||
1183 | struct sock *sk = (void *) arg; | ||
1184 | u16 control; | ||
1185 | |||
1186 | if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { | ||
1187 | l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk); | ||
1188 | return; | ||
1189 | } | ||
1190 | |||
1191 | l2cap_pi(sk)->retry_count++; | ||
1192 | __mod_monitor_timer(); | ||
1193 | |||
1194 | control = L2CAP_CTRL_POLL; | ||
1195 | control |= L2CAP_SUPER_RCV_READY; | ||
1196 | l2cap_send_sframe(l2cap_pi(sk), control); | ||
1197 | } | ||
1198 | |||
1199 | static void l2cap_retrans_timeout(unsigned long arg) | ||
1200 | { | ||
1201 | struct sock *sk = (void *) arg; | ||
1202 | u16 control; | ||
1203 | |||
1204 | l2cap_pi(sk)->retry_count = 1; | ||
1205 | __mod_monitor_timer(); | ||
1206 | |||
1207 | l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; | ||
1208 | |||
1209 | control = L2CAP_CTRL_POLL; | ||
1210 | control |= L2CAP_SUPER_RCV_READY; | ||
1211 | l2cap_send_sframe(l2cap_pi(sk), control); | ||
1212 | } | ||
1213 | |||
1181 | static void l2cap_drop_acked_frames(struct sock *sk) | 1214 | static void l2cap_drop_acked_frames(struct sock *sk) |
1182 | { | 1215 | { |
1183 | struct sk_buff *skb; | 1216 | struct sk_buff *skb; |
@@ -1192,6 +1225,9 @@ static void l2cap_drop_acked_frames(struct sock *sk) | |||
1192 | l2cap_pi(sk)->unacked_frames--; | 1225 | l2cap_pi(sk)->unacked_frames--; |
1193 | } | 1226 | } |
1194 | 1227 | ||
1228 | if (!l2cap_pi(sk)->unacked_frames) | ||
1229 | del_timer(&l2cap_pi(sk)->retrans_timer); | ||
1230 | |||
1195 | return; | 1231 | return; |
1196 | } | 1232 | } |
1197 | 1233 | ||
@@ -1216,19 +1252,32 @@ static int l2cap_ertm_send(struct sock *sk) | |||
1216 | u16 control; | 1252 | u16 control; |
1217 | int err; | 1253 | int err; |
1218 | 1254 | ||
1255 | if (pi->conn_state & L2CAP_CONN_WAIT_F) | ||
1256 | return 0; | ||
1257 | |||
1219 | while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { | 1258 | while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { |
1220 | tx_skb = skb_clone(skb, GFP_ATOMIC); | 1259 | tx_skb = skb_clone(skb, GFP_ATOMIC); |
1221 | 1260 | ||
1261 | if (pi->remote_max_tx && | ||
1262 | bt_cb(skb)->retries == pi->remote_max_tx) { | ||
1263 | l2cap_send_disconn_req(pi->conn, sk); | ||
1264 | break; | ||
1265 | } | ||
1266 | |||
1267 | bt_cb(skb)->retries++; | ||
1268 | |||
1222 | control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); | 1269 | control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); |
1223 | control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) | 1270 | control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) |
1224 | | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); | 1271 | | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); |
1225 | put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); | 1272 | put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); |
1226 | 1273 | ||
1274 | |||
1227 | err = l2cap_do_send(sk, tx_skb); | 1275 | err = l2cap_do_send(sk, tx_skb); |
1228 | if (err < 0) { | 1276 | if (err < 0) { |
1229 | l2cap_send_disconn_req(pi->conn, sk); | 1277 | l2cap_send_disconn_req(pi->conn, sk); |
1230 | return err; | 1278 | return err; |
1231 | } | 1279 | } |
1280 | __mod_retrans_timer(); | ||
1232 | 1281 | ||
1233 | bt_cb(skb)->tx_seq = pi->next_tx_seq; | 1282 | bt_cb(skb)->tx_seq = pi->next_tx_seq; |
1234 | pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; | 1283 | pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; |
@@ -1365,6 +1414,8 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg | |||
1365 | kfree_skb(skb); | 1414 | kfree_skb(skb); |
1366 | return ERR_PTR(err); | 1415 | return ERR_PTR(err); |
1367 | } | 1416 | } |
1417 | |||
1418 | bt_cb(skb)->retries = 0; | ||
1368 | return skb; | 1419 | return skb; |
1369 | } | 1420 | } |
1370 | 1421 | ||
@@ -2058,7 +2109,7 @@ done: | |||
2058 | case L2CAP_MODE_ERTM: | 2109 | case L2CAP_MODE_ERTM: |
2059 | rfc.mode = L2CAP_MODE_ERTM; | 2110 | rfc.mode = L2CAP_MODE_ERTM; |
2060 | rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; | 2111 | rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; |
2061 | rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; | 2112 | rfc.max_transmit = L2CAP_DEFAULT_MAX_TX; |
2062 | rfc.retrans_timeout = 0; | 2113 | rfc.retrans_timeout = 0; |
2063 | rfc.monitor_timeout = 0; | 2114 | rfc.monitor_timeout = 0; |
2064 | rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); | 2115 | rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); |
@@ -2553,6 +2604,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
2553 | l2cap_pi(sk)->next_tx_seq = 0; | 2604 | l2cap_pi(sk)->next_tx_seq = 0; |
2554 | l2cap_pi(sk)->expected_ack_seq = 0; | 2605 | l2cap_pi(sk)->expected_ack_seq = 0; |
2555 | l2cap_pi(sk)->unacked_frames = 0; | 2606 | l2cap_pi(sk)->unacked_frames = 0; |
2607 | |||
2608 | setup_timer(&l2cap_pi(sk)->retrans_timer, | ||
2609 | l2cap_retrans_timeout, (unsigned long) sk); | ||
2610 | setup_timer(&l2cap_pi(sk)->monitor_timer, | ||
2611 | l2cap_monitor_timeout, (unsigned long) sk); | ||
2612 | |||
2556 | __skb_queue_head_init(TX_QUEUE(sk)); | 2613 | __skb_queue_head_init(TX_QUEUE(sk)); |
2557 | l2cap_chan_ready(sk); | 2614 | l2cap_chan_ready(sk); |
2558 | goto unlock; | 2615 | goto unlock; |
@@ -2662,6 +2719,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd | |||
2662 | sk->sk_shutdown = SHUTDOWN_MASK; | 2719 | sk->sk_shutdown = SHUTDOWN_MASK; |
2663 | 2720 | ||
2664 | skb_queue_purge(TX_QUEUE(sk)); | 2721 | skb_queue_purge(TX_QUEUE(sk)); |
2722 | del_timer(&l2cap_pi(sk)->retrans_timer); | ||
2723 | del_timer(&l2cap_pi(sk)->monitor_timer); | ||
2665 | 2724 | ||
2666 | l2cap_chan_del(sk, ECONNRESET); | 2725 | l2cap_chan_del(sk, ECONNRESET); |
2667 | bh_unlock_sock(sk); | 2726 | bh_unlock_sock(sk); |
@@ -2686,6 +2745,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd | |||
2686 | return 0; | 2745 | return 0; |
2687 | 2746 | ||
2688 | skb_queue_purge(TX_QUEUE(sk)); | 2747 | skb_queue_purge(TX_QUEUE(sk)); |
2748 | del_timer(&l2cap_pi(sk)->retrans_timer); | ||
2749 | del_timer(&l2cap_pi(sk)->monitor_timer); | ||
2689 | 2750 | ||
2690 | l2cap_chan_del(sk, 0); | 2751 | l2cap_chan_del(sk, 0); |
2691 | bh_unlock_sock(sk); | 2752 | bh_unlock_sock(sk); |
@@ -2991,9 +3052,26 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str | |||
2991 | 3052 | ||
2992 | switch (rx_control & L2CAP_CTRL_SUPERVISE) { | 3053 | switch (rx_control & L2CAP_CTRL_SUPERVISE) { |
2993 | case L2CAP_SUPER_RCV_READY: | 3054 | case L2CAP_SUPER_RCV_READY: |
2994 | pi->expected_ack_seq = __get_reqseq(rx_control); | 3055 | if (rx_control & L2CAP_CTRL_POLL) { |
2995 | l2cap_drop_acked_frames(sk); | 3056 | u16 control = L2CAP_CTRL_FINAL; |
2996 | l2cap_ertm_send(sk); | 3057 | control |= L2CAP_SUPER_RCV_READY; |
3058 | l2cap_send_sframe(l2cap_pi(sk), control); | ||
3059 | } else if (rx_control & L2CAP_CTRL_FINAL) { | ||
3060 | if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) | ||
3061 | break; | ||
3062 | |||
3063 | pi->conn_state &= ~L2CAP_CONN_WAIT_F; | ||
3064 | del_timer(&pi->monitor_timer); | ||
3065 | |||
3066 | if (pi->unacked_frames > 0) | ||
3067 | __mod_retrans_timer(); | ||
3068 | } else { | ||
3069 | pi->expected_ack_seq = __get_reqseq(rx_control); | ||
3070 | l2cap_drop_acked_frames(sk); | ||
3071 | if (pi->unacked_frames > 0) | ||
3072 | __mod_retrans_timer(); | ||
3073 | l2cap_ertm_send(sk); | ||
3074 | } | ||
2997 | break; | 3075 | break; |
2998 | 3076 | ||
2999 | case L2CAP_SUPER_REJECT: | 3077 | case L2CAP_SUPER_REJECT: |