|
@@ -5043,13 +5043,58 @@ static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
amp_read_loc_assoc_final_data(hdev, hcon);
|
|
|
}
|
|
|
|
|
|
+static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
|
|
|
+ u8 event, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct hci_ev_cmd_complete *ev;
|
|
|
+ struct hci_event_hdr *hdr;
|
|
|
+
|
|
|
+ if (!skb)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (skb->len < sizeof(*hdr)) {
|
|
|
+ BT_ERR("Too short HCI event");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ hdr = (void *) skb->data;
|
|
|
+ skb_pull(skb, HCI_EVENT_HDR_SIZE);
|
|
|
+
|
|
|
+ if (event) {
|
|
|
+ if (hdr->evt != event)
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hdr->evt != HCI_EV_CMD_COMPLETE) {
|
|
|
+ BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (skb->len < sizeof(*ev)) {
|
|
|
+ BT_ERR("Too short cmd_complete event");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ ev = (void *) skb->data;
|
|
|
+ skb_pull(skb, sizeof(*ev));
|
|
|
+
|
|
|
+ if (opcode != __le16_to_cpu(ev->opcode)) {
|
|
|
+ BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode,
|
|
|
+ __le16_to_cpu(ev->opcode));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
{
|
|
|
struct hci_event_hdr *hdr = (void *) skb->data;
|
|
|
hci_req_complete_t req_complete = NULL;
|
|
|
hci_req_complete_skb_t req_complete_skb = NULL;
|
|
|
struct sk_buff *orig_skb = NULL;
|
|
|
- u8 status = 0, event = hdr->evt;
|
|
|
+ u8 status = 0, event = hdr->evt, req_evt = 0;
|
|
|
u16 opcode = HCI_OP_NOP;
|
|
|
|
|
|
if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) {
|
|
@@ -5057,6 +5102,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
opcode = __le16_to_cpu(cmd_hdr->opcode);
|
|
|
hci_req_cmd_complete(hdev, opcode, status, &req_complete,
|
|
|
&req_complete_skb);
|
|
|
+ req_evt = event;
|
|
|
}
|
|
|
|
|
|
/* If it looks like we might end up having to call
|
|
@@ -5250,10 +5296,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (req_complete)
|
|
|
+ if (req_complete) {
|
|
|
req_complete(hdev, status, opcode);
|
|
|
- else if (req_complete_skb)
|
|
|
+ } else if (req_complete_skb) {
|
|
|
+ if (!hci_get_cmd_complete(hdev, opcode, req_evt, orig_skb)) {
|
|
|
+ kfree_skb(orig_skb);
|
|
|
+ orig_skb = NULL;
|
|
|
+ }
|
|
|
req_complete_skb(hdev, status, opcode, orig_skb);
|
|
|
+ }
|
|
|
|
|
|
kfree_skb(orig_skb);
|
|
|
kfree_skb(skb);
|