diff options
-rw-r--r-- | include/net/bluetooth/l2cap.h | 3 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 27 |
2 files changed, 30 insertions, 0 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c695083eee2b..85cf40acc47e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -624,6 +624,9 @@ struct l2cap_conn { | |||
624 | __u32 rx_len; | 624 | __u32 rx_len; |
625 | __u8 tx_ident; | 625 | __u8 tx_ident; |
626 | 626 | ||
627 | struct sk_buff_head pending_rx; | ||
628 | struct work_struct pending_rx_work; | ||
629 | |||
627 | __u8 disc_reason; | 630 | __u8 disc_reason; |
628 | 631 | ||
629 | struct delayed_work security_timer; | 632 | struct delayed_work security_timer; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 317a5737daf6..cd534599fbfa 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1550,6 +1550,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) | |||
1550 | } | 1550 | } |
1551 | 1551 | ||
1552 | mutex_unlock(&conn->chan_lock); | 1552 | mutex_unlock(&conn->chan_lock); |
1553 | |||
1554 | queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); | ||
1553 | } | 1555 | } |
1554 | 1556 | ||
1555 | /* Notify sockets that we cannot guaranty reliability anymore */ | 1557 | /* Notify sockets that we cannot guaranty reliability anymore */ |
@@ -1675,6 +1677,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) | |||
1675 | 1677 | ||
1676 | kfree_skb(conn->rx_skb); | 1678 | kfree_skb(conn->rx_skb); |
1677 | 1679 | ||
1680 | skb_queue_purge(&conn->pending_rx); | ||
1681 | flush_work(&conn->pending_rx_work); | ||
1682 | |||
1678 | l2cap_unregister_all_users(conn); | 1683 | l2cap_unregister_all_users(conn); |
1679 | 1684 | ||
1680 | mutex_lock(&conn->chan_lock); | 1685 | mutex_lock(&conn->chan_lock); |
@@ -6880,9 +6885,16 @@ drop: | |||
6880 | static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | 6885 | static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) |
6881 | { | 6886 | { |
6882 | struct l2cap_hdr *lh = (void *) skb->data; | 6887 | struct l2cap_hdr *lh = (void *) skb->data; |
6888 | struct hci_conn *hcon = conn->hcon; | ||
6883 | u16 cid, len; | 6889 | u16 cid, len; |
6884 | __le16 psm; | 6890 | __le16 psm; |
6885 | 6891 | ||
6892 | if (hcon->state != BT_CONNECTED) { | ||
6893 | BT_DBG("queueing pending rx skb"); | ||
6894 | skb_queue_tail(&conn->pending_rx, skb); | ||
6895 | return; | ||
6896 | } | ||
6897 | |||
6886 | skb_pull(skb, L2CAP_HDR_SIZE); | 6898 | skb_pull(skb, L2CAP_HDR_SIZE); |
6887 | cid = __le16_to_cpu(lh->cid); | 6899 | cid = __le16_to_cpu(lh->cid); |
6888 | len = __le16_to_cpu(lh->len); | 6900 | len = __le16_to_cpu(lh->len); |
@@ -6928,6 +6940,18 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | |||
6928 | } | 6940 | } |
6929 | } | 6941 | } |
6930 | 6942 | ||
6943 | static void process_pending_rx(struct work_struct *work) | ||
6944 | { | ||
6945 | struct l2cap_conn *conn = container_of(work, struct l2cap_conn, | ||
6946 | pending_rx_work); | ||
6947 | struct sk_buff *skb; | ||
6948 | |||
6949 | BT_DBG(""); | ||
6950 | |||
6951 | while ((skb = skb_dequeue(&conn->pending_rx))) | ||
6952 | l2cap_recv_frame(conn, skb); | ||
6953 | } | ||
6954 | |||
6931 | static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) | 6955 | static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) |
6932 | { | 6956 | { |
6933 | struct l2cap_conn *conn = hcon->l2cap_data; | 6957 | struct l2cap_conn *conn = hcon->l2cap_data; |
@@ -6983,6 +7007,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) | |||
6983 | else | 7007 | else |
6984 | INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); | 7008 | INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); |
6985 | 7009 | ||
7010 | skb_queue_head_init(&conn->pending_rx); | ||
7011 | INIT_WORK(&conn->pending_rx_work, process_pending_rx); | ||
7012 | |||
6986 | conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; | 7013 | conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; |
6987 | 7014 | ||
6988 | return conn; | 7015 | return conn; |