Skip to content

Instantly share code, notes, and snippets.

@Vudentz
Created June 29, 2020 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Vudentz/464fb0065a73e5c99bdb66cd2c5a1a2d to your computer and use it in GitHub Desktop.
Save Vudentz/464fb0065a73e5c99bdb66cd2c5a1a2d to your computer and use it in GitHub Desktop.
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d4e28773d378..7bd74d7a07db 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -400,6 +400,7 @@ struct hci_dev {
struct delayed_work le_scan_restart;
struct sk_buff_head rx_q;
+ struct sk_buff_head ev_q;
struct sk_buff_head raw_q;
struct sk_buff_head cmd_q;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2e7bc2da8371..09945ccbdf3a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1589,6 +1589,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
skb_queue_purge(&hdev->cmd_q);
skb_queue_purge(&hdev->rx_q);
+ skb_queue_purge(&hdev->ev_q);
if (hdev->flush)
hdev->flush(hdev);
@@ -1776,6 +1777,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
/* Drop queues */
skb_queue_purge(&hdev->rx_q);
+ skb_queue_purge(&hdev->ev_q);
skb_queue_purge(&hdev->cmd_q);
skb_queue_purge(&hdev->raw_q);
@@ -1847,6 +1849,7 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
/* Drop queues */
skb_queue_purge(&hdev->rx_q);
+ skb_queue_purge(&hdev->ev_q);
skb_queue_purge(&hdev->cmd_q);
/* Avoid potential lockdep warnings from the *_flush() calls by
@@ -3440,6 +3443,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
skb_queue_head_init(&hdev->rx_q);
+ skb_queue_head_init(&hdev->ev_q);
skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q);
@@ -3703,7 +3707,18 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
/* Time stamp */
__net_timestamp(skb);
- skb_queue_tail(&hdev->rx_q, skb);
+ switch (hci_skb_pkt_type(skb)) {
+ case HCI_EVENT_PKT:
+ /* Event packets are queue separately so they be processed
+ * first.
+ */
+ skb_queue_tail(&hdev->ev_q, skb);
+ break;
+ default:
+ skb_queue_tail(&hdev->rx_q, skb);
+ break'
+ }
+
queue_work(hdev->workqueue, &hdev->rx_work);
return 0;
@@ -4640,14 +4655,11 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
}
-static void hci_rx_work(struct work_struct *work)
+static void hci_dequeue(struct hci_dev *dev, struct sk_buff_head *queue)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
struct sk_buff *skb;
- BT_DBG("%s", hdev->name);
-
- while ((skb = skb_dequeue(&hdev->rx_q))) {
+ while ((skb = skb_dequeue(queue))) {
/* Send copy to monitor */
hci_send_to_monitor(hdev, skb);
@@ -4703,6 +4715,17 @@ static void hci_rx_work(struct work_struct *work)
}
}
+static void hci_rx_work(struct work_struct *work)
+{
+ struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
+
+ BT_DBG("%s", hdev->name);
+
+ /* Process HCI event packets so states changes are synchronized */
+ hci_dequeue(hdev, &hdev->ev_q);
+ hci_dequeue(hdev, &hdev->rx_q);
+}
+
static void hci_cmd_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment