aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-05-17 23:53:46 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-06-04 23:34:04 -0400
commitf80842a83ec224e70ebbd11a20832e71e5911b45 (patch)
tree98bf84971775e5deb4aaf647dd1d553aa201d0fc /net/bluetooth/l2cap_core.c
parent63838725c6478102894cfb88feb2a9b1c331855d (diff)
Bluetooth: Handle SREJ requests to resend unacked frames
When a remote device sends an SREJ, retransmit the frame with the corresponding sequence number (subject to special cases with poll and final flags). An SREJ is also an implicit indication the the remote device is not in a busy state. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c70
1 files changed, 69 insertions, 1 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fd324d4cb217..36842a29bb47 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1836,6 +1836,15 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
1836 } 1836 }
1837} 1837}
1838 1838
1839static void l2cap_retransmit(struct l2cap_chan *chan,
1840 struct l2cap_ctrl *control)
1841{
1842 BT_DBG("chan %p, control %p", chan, control);
1843
1844 l2cap_seq_list_append(&chan->retrans_list, control->reqseq);
1845 l2cap_ertm_resend(chan);
1846}
1847
1839static void l2cap_retransmit_all(struct l2cap_chan *chan, 1848static void l2cap_retransmit_all(struct l2cap_chan *chan,
1840 struct l2cap_ctrl *control) 1849 struct l2cap_ctrl *control)
1841{ 1850{
@@ -2532,6 +2541,13 @@ static void l2cap_pass_to_tx(struct l2cap_chan *chan,
2532 l2cap_tx(chan, control, 0, L2CAP_EV_RECV_REQSEQ_AND_FBIT); 2541 l2cap_tx(chan, control, 0, L2CAP_EV_RECV_REQSEQ_AND_FBIT);
2533} 2542}
2534 2543
2544static void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan,
2545 struct l2cap_ctrl *control)
2546{
2547 BT_DBG("chan %p, control %p", chan, control);
2548 l2cap_tx(chan, control, 0, L2CAP_EV_RECV_FBIT);
2549}
2550
2535/* Copy frame to all raw sockets on that connection */ 2551/* Copy frame to all raw sockets on that connection */
2536static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) 2552static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
2537{ 2553{
@@ -4539,7 +4555,59 @@ static int l2cap_rx_queued_iframes(struct l2cap_chan *chan)
4539static void l2cap_handle_srej(struct l2cap_chan *chan, 4555static void l2cap_handle_srej(struct l2cap_chan *chan,
4540 struct l2cap_ctrl *control) 4556 struct l2cap_ctrl *control)
4541{ 4557{
4542 /* Placeholder */ 4558 struct sk_buff *skb;
4559
4560 BT_DBG("chan %p, control %p", chan, control);
4561
4562 if (control->reqseq == chan->next_tx_seq) {
4563 BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
4564 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4565 return;
4566 }
4567
4568 skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
4569
4570 if (skb == NULL) {
4571 BT_DBG("Seq %d not available for retransmission",
4572 control->reqseq);
4573 return;
4574 }
4575
4576 if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) {
4577 BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
4578 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4579 return;
4580 }
4581
4582 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4583
4584 if (control->poll) {
4585 l2cap_pass_to_tx(chan, control);
4586
4587 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4588 l2cap_retransmit(chan, control);
4589 l2cap_ertm_send(chan);
4590
4591 if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
4592 set_bit(CONN_SREJ_ACT, &chan->conn_state);
4593 chan->srej_save_reqseq = control->reqseq;
4594 }
4595 } else {
4596 l2cap_pass_to_tx_fbit(chan, control);
4597
4598 if (control->final) {
4599 if (chan->srej_save_reqseq != control->reqseq ||
4600 !test_and_clear_bit(CONN_SREJ_ACT,
4601 &chan->conn_state))
4602 l2cap_retransmit(chan, control);
4603 } else {
4604 l2cap_retransmit(chan, control);
4605 if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
4606 set_bit(CONN_SREJ_ACT, &chan->conn_state);
4607 chan->srej_save_reqseq = control->reqseq;
4608 }
4609 }
4610 }
4543} 4611}
4544 4612
4545static void l2cap_handle_rej(struct l2cap_chan *chan, 4613static void l2cap_handle_rej(struct l2cap_chan *chan,