Bluetooth: hci_core: Introduce hci_recv_event_data
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 4 Feb 2022 21:04:38 +0000 (13:04 -0800)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 22 Jul 2022 20:20:52 +0000 (13:20 -0700)
This introduces hci_recv_event_data to make it simpler to access the
contents of last received event rather than having to pass its contents
to the likes of *_ind/*_cfm callbacks.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c

index df65b10..6569b12 100644 (file)
@@ -525,6 +525,7 @@ struct hci_dev {
        struct sk_buff_head     cmd_q;
 
        struct sk_buff          *sent_cmd;
+       struct sk_buff          *recv_event;
 
        struct mutex            req_lock;
        wait_queue_head_t       req_wait_q;
@@ -1747,6 +1748,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
+void *hci_recv_event_data(struct hci_dev *hdev, __u8 event);
 
 u32 hci_conn_get_phy(struct hci_conn *conn);
 
index e42824e..924c295 100644 (file)
@@ -2712,6 +2712,7 @@ void hci_release_dev(struct hci_dev *hdev)
 
        ida_simple_remove(&hci_index_ida, hdev->id);
        kfree_skb(hdev->sent_cmd);
+       kfree_skb(hdev->recv_event);
        kfree(hdev);
 }
 EXPORT_SYMBOL(hci_release_dev);
@@ -3018,6 +3019,37 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
        return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
 
+/* Get data from last received event */
+void *hci_recv_event_data(struct hci_dev *hdev, __u8 event)
+{
+       struct hci_event_hdr *hdr;
+       int offset;
+
+       if (!hdev->recv_event)
+               return NULL;
+
+       hdr = (void *)hdev->recv_event->data;
+       offset = sizeof(*hdr);
+
+       if (hdr->evt != event) {
+               /* In case of LE metaevent check the subevent match */
+               if (hdr->evt == HCI_EV_LE_META) {
+                       struct hci_ev_le_meta *ev;
+
+                       ev = (void *)hdev->recv_event->data + offset;
+                       offset += sizeof(*ev);
+                       if (ev->subevent == event)
+                               goto found;
+               }
+               return NULL;
+       }
+
+found:
+       bt_dev_dbg(hdev, "event 0x%2.2x", event);
+
+       return hdev->recv_event->data + offset;
+}
+
 /* Send ACL data */
 static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
 {
index b32ca92..bab52ee 100644 (file)
@@ -6936,6 +6936,9 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                goto done;
        }
 
+       kfree_skb(hdev->recv_event);
+       hdev->recv_event = skb_clone(skb, GFP_KERNEL);
+
        event = hdr->evt;
        if (!event) {
                bt_dev_warn(hdev, "Received unexpected HCI Event 0x%2.2x",