Skip to content

Commit

Permalink
Bluetooth: Handle L2CAP case when the remote receiver is busy
Browse files Browse the repository at this point in the history
Implement all issues related to RemoteBusy in the RECV state table.

Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
Gustavo F. Padovan authored and Marcel Holtmann committed Aug 26, 2009
1 parent ca42a61 commit 2246b2f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
2 changes: 2 additions & 0 deletions include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ struct l2cap_pinfo {
#define L2CAP_CONN_WAIT_F 0x04
#define L2CAP_CONN_SREJ_ACT 0x08
#define L2CAP_CONN_SEND_PBIT 0x10
#define L2CAP_CONN_REMOTE_BUSY 0x20
#define L2CAP_CONN_LOCAL_BUSY 0x40

#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
Expand Down
25 changes: 23 additions & 2 deletions net/bluetooth/l2cap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,8 @@ static int l2cap_ertm_send(struct sock *sk)
if (pi->conn_state & L2CAP_CONN_WAIT_F)
return 0;

while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))
&& !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
tx_skb = skb_clone(skb, GFP_ATOMIC);

if (pi->remote_max_tx &&
Expand Down Expand Up @@ -3351,7 +3352,10 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
control |= L2CAP_SUPER_RCV_READY |
(pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT);
l2cap_send_sframe(l2cap_pi(sk), control);
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;

} else if (rx_control & L2CAP_CTRL_FINAL) {
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);

Expand All @@ -3366,13 +3370,19 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
} else {
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
if (pi->unacked_frames > 0)

if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
&& (pi->unacked_frames > 0))
__mod_retrans_timer();

l2cap_ertm_send(sk);
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
}
break;

case L2CAP_SUPER_REJECT:
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;

pi->expected_ack_seq = __get_reqseq(rx_control);
l2cap_drop_acked_frames(sk);

Expand All @@ -3384,6 +3394,8 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
break;

case L2CAP_SUPER_SELECT_REJECT:
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;

if (rx_control & L2CAP_CTRL_POLL) {
l2cap_retransmit_frame(sk, tx_seq);
pi->expected_ack_seq = tx_seq;
Expand All @@ -3410,6 +3422,15 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
break;

case L2CAP_SUPER_RCV_NOT_READY:
pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);

del_timer(&l2cap_pi(sk)->retrans_timer);
if (rx_control & L2CAP_CTRL_POLL) {
u16 control = L2CAP_CTRL_FINAL | L2CAP_SUPER_RCV_READY;
l2cap_send_sframe(l2cap_pi(sk), control);
}
break;
}

Expand Down

0 comments on commit 2246b2f

Please sign in to comment.