summaryrefslogtreecommitdiff
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2011-07-07 09:39:02 -0700
committerGustavo F. Padovan <padovan@profusion.mobi>2011-07-07 15:28:56 -0300
commite328140fdacbba43292a59a22fb55d9185288318 (patch)
tree43eb760529846562e6e75c25cd39a8317142eac7 /net/bluetooth/l2cap_core.c
parent26f880d221302b5d061185d8a6795bb532693bf3 (diff)
downloadlwn-e328140fdacbba43292a59a22fb55d9185288318.tar.gz
lwn-e328140fdacbba43292a59a22fb55d9185288318.zip
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
}
err = l2cap_ertm_reassembly_sdu(chan, skb, control);
- if (err >= 0) {
- chan->buffer_seq = (chan->buffer_seq + 1) % 64;
- return err;
- }
-
- l2cap_ertm_enter_local_busy(chan);
-
- bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
- __skb_queue_tail(&chan->busy_q, skb);
-
- queue_work(_busy_wq, &chan->busy_work);
+ chan->buffer_seq = (chan->buffer_seq + 1) % 64;
return err;
}
+void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
+{
+ if (chan->mode == L2CAP_MODE_ERTM) {
+ if (busy)
+ l2cap_ertm_enter_local_busy(chan);
+ else
+ l2cap_ertm_exit_local_busy(chan);
+ }
+}
+
static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
struct sk_buff *_skb;
@@ -3463,13 +3463,22 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
struct sk_buff *skb;
u16 control;
- while ((skb = skb_peek(&chan->srej_q))) {
+ while ((skb = skb_peek(&chan->srej_q)) &&
+ !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+ int err;
+
if (bt_cb(skb)->tx_seq != tx_seq)
break;
skb = skb_dequeue(&chan->srej_q);
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
- l2cap_ertm_reassembly_sdu(chan, skb, control);
+ err = l2cap_ertm_reassembly_sdu(chan, skb, control);
+
+ if (err < 0) {
+ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+ break;
+ }
+
chan->buffer_seq_srej =
(chan->buffer_seq_srej + 1) % 64;
tx_seq = (tx_seq + 1) % 64;
@@ -3625,8 +3634,10 @@ expected:
}
err = l2cap_push_rx_skb(chan, skb, rx_control);
- if (err < 0)
- return 0;
+ if (err < 0) {
+ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+ return err;
+ }
if (rx_control & L2CAP_CTRL_FINAL) {
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))