diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2015-04-02 12:41:12 +0200 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-04-02 16:09:28 +0200 |
commit | 757aa0b56da5d1089c55bf349fa15836dae22b6f (patch) | |
tree | 7d5b7dd93801eaac90f3c8323ebf1a033349db6e /net/bluetooth/hci_event.c | |
parent | Bluetooth: Remove unused hci_req_pending() function (diff) | |
download | linux-757aa0b56da5d1089c55bf349fa15836dae22b6f.tar.xz linux-757aa0b56da5d1089c55bf349fa15836dae22b6f.zip |
Bluetooth: Move hci_get_cmd_complete() to hci_event.c
To make the hci_req_run_skb() API consistent with hci_cmd_sync_ev()
the callback should receive the cmd_complete parameters in the 'normal'
case and the full HCI event if a special event was expected. This patch
moves the hci_get_cmd_complete() function from hci_core.c to hci_event.c
where it's used to strip the skb from the needed headers before passing
it on to the callback.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_event.c')
-rw-r--r-- | net/bluetooth/hci_event.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index dc9547c11c45..c2483cb6ffbd 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -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); |