|
@@ -61,13 +61,9 @@ int disable_ertm;
|
|
|
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
|
|
|
static u8 l2cap_fixed_chan[8] = { 0x02, };
|
|
|
|
|
|
-static struct workqueue_struct *_busy_wq;
|
|
|
-
|
|
|
static LIST_HEAD(chan_list);
|
|
|
static DEFINE_RWLOCK(chan_list_lock);
|
|
|
|
|
|
-static void l2cap_busy_work(struct work_struct *work);
|
|
|
-
|
|
|
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
|
|
u8 code, u8 ident, u16 dlen, void *data);
|
|
|
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
|
|
@@ -395,7 +391,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
|
|
__clear_ack_timer(chan);
|
|
|
|
|
|
skb_queue_purge(&chan->srej_q);
|
|
|
- skb_queue_purge(&chan->busy_q);
|
|
|
|
|
|
list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
|
|
|
list_del(&l->list);
|
|
@@ -1873,11 +1868,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
|
|
|
setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
|
|
|
|
|
|
skb_queue_head_init(&chan->srej_q);
|
|
|
- skb_queue_head_init(&chan->busy_q);
|
|
|
|
|
|
INIT_LIST_HEAD(&chan->srej_l);
|
|
|
|
|
|
- INIT_WORK(&chan->busy_work, l2cap_busy_work);
|
|
|
|
|
|
sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
|
|
|
}
|
|
@@ -3182,32 +3175,27 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
|
|
|
if (!chan->sdu)
|
|
|
goto disconnect;
|
|
|
|
|
|
- if (!test_bit(CONN_SAR_RETRY, &chan->conn_state)) {
|
|
|
- chan->partial_sdu_len += skb->len;
|
|
|
+ chan->partial_sdu_len += skb->len;
|
|
|
|
|
|
- if (chan->partial_sdu_len > chan->imtu)
|
|
|
- goto drop;
|
|
|
+ if (chan->partial_sdu_len > chan->imtu)
|
|
|
+ goto drop;
|
|
|
|
|
|
- if (chan->partial_sdu_len != chan->sdu_len)
|
|
|
- goto drop;
|
|
|
+ if (chan->partial_sdu_len != chan->sdu_len)
|
|
|
+ goto drop;
|
|
|
|
|
|
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
|
|
|
- }
|
|
|
+ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
|
|
|
|
|
|
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
|
|
|
if (!_skb) {
|
|
|
- set_bit(CONN_SAR_RETRY, &chan->conn_state);
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
err = chan->ops->recv(chan->data, _skb);
|
|
|
if (err < 0) {
|
|
|
kfree_skb(_skb);
|
|
|
- set_bit(CONN_SAR_RETRY, &chan->conn_state);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- clear_bit(CONN_SAR_RETRY, &chan->conn_state);
|
|
|
clear_bit(CONN_SAR_SDU, &chan->conn_state);
|
|
|
|
|
|
kfree_skb(chan->sdu);
|
|
@@ -3268,93 +3256,6 @@ done:
|
|
|
BT_DBG("chan %p, Exit local busy", chan);
|
|
|
}
|
|
|
|
|
|
-static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
|
|
|
-{
|
|
|
- struct sk_buff *skb;
|
|
|
- u16 control;
|
|
|
- int err;
|
|
|
-
|
|
|
- while ((skb = skb_dequeue(&chan->busy_q))) {
|
|
|
- control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
|
|
|
- err = l2cap_ertm_reassembly_sdu(chan, skb, control);
|
|
|
- if (err < 0) {
|
|
|
- skb_queue_head(&chan->busy_q, skb);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- chan->buffer_seq = (chan->buffer_seq + 1) % 64;
|
|
|
- }
|
|
|
-
|
|
|
- l2cap_ertm_exit_local_busy(chan);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void l2cap_busy_work(struct work_struct *work)
|
|
|
-{
|
|
|
- DECLARE_WAITQUEUE(wait, current);
|
|
|
- struct l2cap_chan *chan =
|
|
|
- container_of(work, struct l2cap_chan, busy_work);
|
|
|
- struct sock *sk = chan->sk;
|
|
|
- int n_tries = 0, timeo = HZ/5, err;
|
|
|
- struct sk_buff *skb;
|
|
|
-
|
|
|
- lock_sock(sk);
|
|
|
-
|
|
|
- add_wait_queue(sk_sleep(sk), &wait);
|
|
|
- while ((skb = skb_peek(&chan->busy_q))) {
|
|
|
- set_current_state(TASK_INTERRUPTIBLE);
|
|
|
-
|
|
|
- if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
|
|
|
- err = -EBUSY;
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, EBUSY);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (!timeo)
|
|
|
- timeo = HZ/5;
|
|
|
-
|
|
|
- if (signal_pending(current)) {
|
|
|
- err = sock_intr_errno(timeo);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- release_sock(sk);
|
|
|
- timeo = schedule_timeout(timeo);
|
|
|
- lock_sock(sk);
|
|
|
-
|
|
|
- err = sock_error(sk);
|
|
|
- if (err)
|
|
|
- break;
|
|
|
-
|
|
|
- if (l2cap_try_push_rx_skb(chan) == 0)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- set_current_state(TASK_RUNNING);
|
|
|
- remove_wait_queue(sk_sleep(sk), &wait);
|
|
|
-
|
|
|
- release_sock(sk);
|
|
|
-}
|
|
|
-
|
|
|
-static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
|
|
|
-{
|
|
|
- int err;
|
|
|
-
|
|
|
- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
|
|
|
- bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
|
|
|
- __skb_queue_tail(&chan->busy_q, skb);
|
|
|
- return l2cap_try_push_rx_skb(chan);
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- err = l2cap_ertm_reassembly_sdu(chan, skb, control);
|
|
|
- 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) {
|
|
@@ -3612,7 +3513,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
|
|
|
chan->buffer_seq_srej = chan->buffer_seq;
|
|
|
|
|
|
__skb_queue_head_init(&chan->srej_q);
|
|
|
- __skb_queue_head_init(&chan->busy_q);
|
|
|
l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
|
|
|
|
|
|
set_bit(CONN_SEND_PBIT, &chan->conn_state);
|
|
@@ -3633,7 +3533,8 @@ expected:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- err = l2cap_push_rx_skb(chan, skb, rx_control);
|
|
|
+ err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control);
|
|
|
+ chan->buffer_seq = (chan->buffer_seq + 1) % 64;
|
|
|
if (err < 0) {
|
|
|
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
return err;
|
|
@@ -4439,12 +4340,6 @@ int __init l2cap_init(void)
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|
|
|
- _busy_wq = create_singlethread_workqueue("l2cap");
|
|
|
- if (!_busy_wq) {
|
|
|
- err = -ENOMEM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
err = hci_register_proto(&l2cap_hci_proto);
|
|
|
if (err < 0) {
|
|
|
BT_ERR("L2CAP protocol registration failed");
|
|
@@ -4462,7 +4357,6 @@ int __init l2cap_init(void)
|
|
|
return 0;
|
|
|
|
|
|
error:
|
|
|
- destroy_workqueue(_busy_wq);
|
|
|
l2cap_cleanup_sockets();
|
|
|
return err;
|
|
|
}
|
|
@@ -4471,9 +4365,6 @@ void l2cap_exit(void)
|
|
|
{
|
|
|
debugfs_remove(l2cap_debugfs);
|
|
|
|
|
|
- flush_workqueue(_busy_wq);
|
|
|
- destroy_workqueue(_busy_wq);
|
|
|
-
|
|
|
if (hci_unregister_proto(&l2cap_hci_proto) < 0)
|
|
|
BT_ERR("L2CAP protocol unregistration failed");
|
|
|
|