Commit 61a939c6 authored by Johan Hedberg's avatar Johan Hedberg

Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached

This patch adds a queue for incoming L2CAP data that's received before
l2cap_connect_cfm is called and processes the data once
l2cap_connect_cfm is called. This way we ensure that we have e.g. all
remote features before processing L2CAP signaling data (which is very
important for making the correct security decisions).

The processing of the pending rx data needs to be done through
queue_work since unlike l2cap_recv_acldata, l2cap_connect_cfm is called
with the hci_dev lock held which could cause potential deadlocks.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 162b49e7
...@@ -624,6 +624,9 @@ struct l2cap_conn { ...@@ -624,6 +624,9 @@ struct l2cap_conn {
__u32 rx_len; __u32 rx_len;
__u8 tx_ident; __u8 tx_ident;
struct sk_buff_head pending_rx;
struct work_struct pending_rx_work;
__u8 disc_reason; __u8 disc_reason;
struct delayed_work security_timer; struct delayed_work security_timer;
......
...@@ -1550,6 +1550,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) ...@@ -1550,6 +1550,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
} }
mutex_unlock(&conn->chan_lock); mutex_unlock(&conn->chan_lock);
queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
} }
/* Notify sockets that we cannot guaranty reliability anymore */ /* Notify sockets that we cannot guaranty reliability anymore */
...@@ -1675,6 +1677,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) ...@@ -1675,6 +1677,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree_skb(conn->rx_skb); kfree_skb(conn->rx_skb);
skb_queue_purge(&conn->pending_rx);
flush_work(&conn->pending_rx_work);
l2cap_unregister_all_users(conn); l2cap_unregister_all_users(conn);
mutex_lock(&conn->chan_lock); mutex_lock(&conn->chan_lock);
...@@ -6880,9 +6885,16 @@ static void l2cap_att_channel(struct l2cap_conn *conn, ...@@ -6880,9 +6885,16 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
struct l2cap_hdr *lh = (void *) skb->data; struct l2cap_hdr *lh = (void *) skb->data;
struct hci_conn *hcon = conn->hcon;
u16 cid, len; u16 cid, len;
__le16 psm; __le16 psm;
if (hcon->state != BT_CONNECTED) {
BT_DBG("queueing pending rx skb");
skb_queue_tail(&conn->pending_rx, skb);
return;
}
skb_pull(skb, L2CAP_HDR_SIZE); skb_pull(skb, L2CAP_HDR_SIZE);
cid = __le16_to_cpu(lh->cid); cid = __le16_to_cpu(lh->cid);
len = __le16_to_cpu(lh->len); len = __le16_to_cpu(lh->len);
...@@ -6928,6 +6940,18 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -6928,6 +6940,18 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
} }
} }
static void process_pending_rx(struct work_struct *work)
{
struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
pending_rx_work);
struct sk_buff *skb;
BT_DBG("");
while ((skb = skb_dequeue(&conn->pending_rx)))
l2cap_recv_frame(conn, skb);
}
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
{ {
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
...@@ -6983,6 +7007,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) ...@@ -6983,6 +7007,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
else else
INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
skb_queue_head_init(&conn->pending_rx);
INIT_WORK(&conn->pending_rx_work, process_pending_rx);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
return conn; return conn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment