aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2011-07-07 12:39:02 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-07-07 14:28:56 -0400
commite328140fdacbba43292a59a22fb55d9185288318 (patch)
tree43eb760529846562e6e75c25cd39a8317142eac7 /net/bluetooth/l2cap_core.c
parent26f880d221302b5d061185d8a6795bb532693bf3 (diff)
Bluetooth: Use event-driven approach for handling ERTM receive buffer
This change moves most L2CAP ERTM receive buffer handling out of the L2CAP core and in to the socket code. It's up to the higher layer (the socket code, in this case) to tell the core when its buffer is full or has space available. The recv op should always accept incoming ERTM data or else the connection will go down. Within the socket layer, an skb that does not fit in the socket receive buffer will be temporarily stored. When the socket is read from, that skb will be placed in the receive buffer if possible. Once adequate buffer space becomes available, the L2CAP core is informed and the ERTM local busy state is cleared. Receive buffer management for non-ERTM modes is unchanged. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f7ada4a2cc5d..ea9c7d061046 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3350,21 +3350,21 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
3350 } 3350 }
3351 3351
3352 err = l2cap_ertm_reassembly_sdu(chan, skb, control); 3352 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
3353 if (err >= 0) { 3353 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
3354 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
3355 return err;
3356 }
3357
3358 l2cap_ertm_enter_local_busy(chan);
3359
3360 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
3361 __skb_queue_tail(&chan->busy_q, skb);
3362
3363 queue_work(_busy_wq, &chan->busy_work);
3364 3354
3365 return err; 3355 return err;
3366} 3356}
3367 3357
3358void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
3359{
3360 if (chan->mode == L2CAP_MODE_ERTM) {
3361 if (busy)
3362 l2cap_ertm_enter_local_busy(chan);
3363 else
3364 l2cap_ertm_exit_local_busy(chan);
3365 }
3366}
3367
3368static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) 3368static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
3369{ 3369{
3370 struct sk_buff *_skb; 3370 struct sk_buff *_skb;
@@ -3463,13 +3463,22 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
3463 struct sk_buff *skb; 3463 struct sk_buff *skb;
3464 u16 control; 3464 u16 control;
3465 3465
3466 while ((skb = skb_peek(&chan->srej_q))) { 3466 while ((skb = skb_peek(&chan->srej_q)) &&
3467 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3468 int err;
3469
3467 if (bt_cb(skb)->tx_seq != tx_seq) 3470 if (bt_cb(skb)->tx_seq != tx_seq)
3468 break; 3471 break;
3469 3472
3470 skb = skb_dequeue(&chan->srej_q); 3473 skb = skb_dequeue(&chan->srej_q);
3471 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; 3474 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
3472 l2cap_ertm_reassembly_sdu(chan, skb, control); 3475 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
3476
3477 if (err < 0) {
3478 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3479 break;
3480 }
3481
3473 chan->buffer_seq_srej = 3482 chan->buffer_seq_srej =
3474 (chan->buffer_seq_srej + 1) % 64; 3483 (chan->buffer_seq_srej + 1) % 64;
3475 tx_seq = (tx_seq + 1) % 64; 3484 tx_seq = (tx_seq + 1) % 64;
@@ -3625,8 +3634,10 @@ expected:
3625 } 3634 }
3626 3635
3627 err = l2cap_push_rx_skb(chan, skb, rx_control); 3636 err = l2cap_push_rx_skb(chan, skb, rx_control);
3628 if (err < 0) 3637 if (err < 0) {
3629 return 0; 3638 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3639 return err;
3640 }
3630 3641
3631 if (rx_control & L2CAP_CTRL_FINAL) { 3642 if (rx_control & L2CAP_CTRL_FINAL) {
3632 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) 3643 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))