aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap_core.c62
1 files changed, 38 insertions, 24 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index bd5d9926bf4f..f7ada4a2cc5d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3227,22 +3227,26 @@ disconnect:
3227 return 0; 3227 return 0;
3228} 3228}
3229 3229
3230static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) 3230static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
3231{ 3231{
3232 struct sk_buff *skb;
3233 u16 control; 3232 u16 control;
3234 int err;
3235 3233
3236 while ((skb = skb_dequeue(&chan->busy_q))) { 3234 BT_DBG("chan %p, Enter local busy", chan);
3237 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
3238 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
3239 if (err < 0) {
3240 skb_queue_head(&chan->busy_q, skb);
3241 return -EBUSY;
3242 }
3243 3235
3244 chan->buffer_seq = (chan->buffer_seq + 1) % 64; 3236 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3245 } 3237
3238 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
3239 control |= L2CAP_SUPER_RCV_NOT_READY;
3240 l2cap_send_sframe(chan, control);
3241
3242 set_bit(CONN_RNR_SENT, &chan->conn_state);
3243
3244 __clear_ack_timer(chan);
3245}
3246
3247static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3248{
3249 u16 control;
3246 3250
3247 if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) 3251 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3248 goto done; 3252 goto done;
@@ -3262,6 +3266,26 @@ done:
3262 clear_bit(CONN_RNR_SENT, &chan->conn_state); 3266 clear_bit(CONN_RNR_SENT, &chan->conn_state);
3263 3267
3264 BT_DBG("chan %p, Exit local busy", chan); 3268 BT_DBG("chan %p, Exit local busy", chan);
3269}
3270
3271static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
3272{
3273 struct sk_buff *skb;
3274 u16 control;
3275 int err;
3276
3277 while ((skb = skb_dequeue(&chan->busy_q))) {
3278 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
3279 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
3280 if (err < 0) {
3281 skb_queue_head(&chan->busy_q, skb);
3282 return -EBUSY;
3283 }
3284
3285 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
3286 }
3287
3288 l2cap_ertm_exit_local_busy(chan);
3265 3289
3266 return 0; 3290 return 0;
3267} 3291}
@@ -3315,7 +3339,7 @@ static void l2cap_busy_work(struct work_struct *work)
3315 3339
3316static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) 3340static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
3317{ 3341{
3318 int sctrl, err; 3342 int err;
3319 3343
3320 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { 3344 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3321 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; 3345 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
@@ -3331,21 +3355,11 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
3331 return err; 3355 return err;
3332 } 3356 }
3333 3357
3334 /* Busy Condition */ 3358 l2cap_ertm_enter_local_busy(chan);
3335 BT_DBG("chan %p, Enter local busy", chan);
3336 3359
3337 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3338 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; 3360 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
3339 __skb_queue_tail(&chan->busy_q, skb); 3361 __skb_queue_tail(&chan->busy_q, skb);
3340 3362
3341 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
3342 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
3343 l2cap_send_sframe(chan, sctrl);
3344
3345 set_bit(CONN_RNR_SENT, &chan->conn_state);
3346
3347 __clear_ack_timer(chan);
3348
3349 queue_work(_busy_wq, &chan->busy_work); 3363 queue_work(_busy_wq, &chan->busy_work);
3350 3364
3351 return err; 3365 return err;