Bluetooth: hci_sync: Add support for waiting specific LE subevents
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 22 Dec 2021 20:21:57 +0000 (12:21 -0800)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 22 Dec 2021 22:01:35 +0000 (23:01 +0100)
This adds support for waiting for specific LE subevents instead of
command status which may only indicate that the commands is in progress
and a different event is used to complete the operation.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/bluetooth.h
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c

index 7790683..4b3d0b1 100644 (file)
@@ -412,6 +412,7 @@ struct bt_skb_cb {
 #define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
 #define hci_skb_expect(skb) bt_cb((skb))->expect
 #define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
+#define hci_skb_event(skb) bt_cb((skb))->hci.req_event
 #define hci_skb_sk(skb) bt_cb((skb))->hci.sk
 
 static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
index ca8e022..f1082b7 100644 (file)
@@ -4038,15 +4038,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, void *data,
         * (since for this kind of commands there will not be a command
         * complete event).
         */
-       if (ev->status ||
-           (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->hci.req_event))
+       if (ev->status || (hdev->sent_cmd && !hci_skb_event(hdev->sent_cmd))) {
                hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete,
                                     req_complete_skb);
-
-       if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) {
-               bt_dev_err(hdev,
-                          "unexpected event for opcode 0x%4.4x", *opcode);
-               return;
+               if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) {
+                       bt_dev_err(hdev, "unexpected event for opcode 0x%4.4x",
+                                  *opcode);
+                       return;
+               }
        }
 
        if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q))
@@ -6464,13 +6463,24 @@ static const struct hci_le_ev {
 };
 
 static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
-                           struct sk_buff *skb)
+                           struct sk_buff *skb, u16 *opcode, u8 *status,
+                           hci_req_complete_t *req_complete,
+                           hci_req_complete_skb_t *req_complete_skb)
 {
        struct hci_ev_le_meta *ev = data;
        const struct hci_le_ev *subev;
 
        bt_dev_dbg(hdev, "subevent 0x%2.2x", ev->subevent);
 
+       /* Only match event if command OGF is for LE */
+       if (hdev->sent_cmd &&
+           hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) == 0x08 &&
+           hci_skb_event(hdev->sent_cmd) == ev->subevent) {
+               *opcode = hci_skb_opcode(hdev->sent_cmd);
+               hci_req_cmd_complete(hdev, *opcode, 0x00, req_complete,
+                                    req_complete_skb);
+       }
+
        subev = &hci_le_ev_table[ev->subevent];
        if (!subev->func)
                return;
@@ -6764,8 +6774,8 @@ static const struct hci_ev {
        HCI_EV(HCI_EV_REMOTE_HOST_FEATURES, hci_remote_host_features_evt,
               sizeof(struct hci_ev_remote_host_features)),
        /* [0x3e = HCI_EV_LE_META] */
-       HCI_EV_VL(HCI_EV_LE_META, hci_le_meta_evt,
-                 sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
+       HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
+                     sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
 #if IS_ENABLED(CONFIG_BT_HS)
        /* [0x40 = HCI_EV_PHY_LINK_COMPLETE] */
        HCI_EV(HCI_EV_PHY_LINK_COMPLETE, hci_phy_link_complete_evt,
@@ -6849,11 +6859,12 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                goto done;
        }
 
-       if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->hci.req_event == event) {
-               struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data;
-               opcode = __le16_to_cpu(cmd_hdr->opcode);
-               hci_req_cmd_complete(hdev, opcode, status, &req_complete,
-                                    &req_complete_skb);
+       /* Only match event if command OGF is not for LE */
+       if (hdev->sent_cmd &&
+           hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) != 0x08 &&
+           hci_skb_event(hdev->sent_cmd) == event) {
+               hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->sent_cmd),
+                                    status, &req_complete, &req_complete_skb);
                req_evt = event;
        }
 
index a3cf848..334dc5f 100644 (file)
@@ -103,7 +103,7 @@ static void hci_cmd_sync_add(struct hci_request *req, u16 opcode, u32 plen,
        if (skb_queue_empty(&req->cmd_q))
                bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
 
-       bt_cb(skb)->hci.req_event = event;
+       hci_skb_event(skb) = event;
 
        skb_queue_tail(&req->cmd_q, skb);
 }