Bluetooth: hci_event: Use of a function table to handle Command Complete
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 1 Dec 2021 18:55:05 +0000 (10:55 -0800)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 7 Dec 2021 16:05:50 +0000 (17:05 +0100)
This change the use of switch statement to a function table which is
easier to extend and can include min/max length of each command.

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

index cecd81e..313b7b7 100644 (file)
@@ -81,14 +81,10 @@ static void *hci_le_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
        return data;
 }
 
-static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
-                                 u8 *new_status)
+static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,
+                               struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_INQUIRY_CANCEL, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
@@ -104,10 +100,8 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
                rp->status = 0x00;
        }
 
-       *new_status = rp->status;
-
        if (rp->status)
-               return;
+               return rp->status;
 
        clear_bit(HCI_INQUIRY, &hdev->flags);
        smp_mb__after_atomic(); /* wake_up_bit advises about this barrier */
@@ -123,68 +117,62 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
        hci_dev_unlock(hdev);
 
        hci_conn_check_pending(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_periodic_inq(struct hci_dev *hdev, void *data,
+                             struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_PERIODIC_INQ, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_set_flag(hdev, HCI_PERIODIC_INQ);
+
+       return rp->status;
 }
 
-static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_exit_periodic_inq(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_EXIT_PERIODIC_INQ, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ);
 
        hci_conn_check_pending(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_remote_name_req_cancel(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_REMOTE_NAME_REQ_CANCEL,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
+
+       return rp->status;
 }
 
-static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_role_discovery(struct hci_dev *hdev, void *data,
+                               struct sk_buff *skb)
 {
-       struct hci_rp_role_discovery *rp;
+       struct hci_rp_role_discovery *rp = data;
        struct hci_conn *conn;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_ROLE_DISCOVERY, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -193,21 +181,20 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
                conn->role = rp->role;
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_link_policy(struct hci_dev *hdev, void *data,
+                                 struct sk_buff *skb)
 {
-       struct hci_rp_read_link_policy *rp;
+       struct hci_rp_read_link_policy *rp = data;
        struct hci_conn *conn;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LINK_POLICY, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -216,26 +203,25 @@ static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
                conn->link_policy = __le16_to_cpu(rp->policy);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_link_policy(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_rp_write_link_policy *rp;
+       struct hci_rp_write_link_policy *rp = data;
        struct hci_conn *conn;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_LINK_POLICY, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -244,63 +230,55 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
                conn->link_policy = get_unaligned_le16(sent + 2);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_read_def_link_policy(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_rp_read_def_link_policy *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_DEF_LINK_POLICY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_def_link_policy *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->link_policy = __le16_to_cpu(rp->policy);
+
+       return rp->status;
 }
 
-static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_write_def_link_policy(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_DEF_LINK_POLICY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
        if (!sent)
-               return;
+               return rp->status;
 
        hdev->link_policy = get_unaligned_le16(sent);
+
+       return rp->status;
 }
 
-static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_reset(struct hci_dev *hdev, void *data, struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_RESET, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        clear_bit(HCI_RESET, &hdev->flags);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        /* Reset all non-persistent flags */
        hci_dev_clear_volatile_flags(hdev);
@@ -322,66 +300,59 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_bdaddr_list_clear(&hdev->le_accept_list);
        hci_bdaddr_list_clear(&hdev->le_resolv_list);
+
+       return rp->status;
 }
 
-static void hci_cc_read_stored_link_key(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_read_stored_link_key(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_rp_read_stored_link_key *rp;
+       struct hci_rp_read_stored_link_key *rp = data;
        struct hci_cp_read_stored_link_key *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_STORED_LINK_KEY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_READ_STORED_LINK_KEY);
        if (!sent)
-               return;
+               return rp->status;
 
        if (!rp->status && sent->read_all == 0x01) {
                hdev->stored_max_keys = le16_to_cpu(rp->max_keys);
                hdev->stored_num_keys = le16_to_cpu(rp->num_keys);
        }
+
+       return rp->status;
 }
 
-static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_delete_stored_link_key(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_delete_stored_link_key *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_DELETE_STORED_LINK_KEY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_delete_stored_link_key *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (rp->num_keys <= hdev->stored_num_keys)
                hdev->stored_num_keys -= le16_to_cpu(rp->num_keys);
        else
                hdev->stored_num_keys = 0;
+
+       return rp->status;
 }
 
-static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_local_name(struct hci_dev *hdev, void *data,
+                                 struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_LOCAL_NAME, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -391,40 +362,38 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
                memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_local_name(struct hci_dev *hdev, void *data,
+                                struct sk_buff *skb)
 {
-       struct hci_rp_read_local_name *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_NAME, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_name *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (hci_dev_test_flag(hdev, HCI_SETUP) ||
            hci_dev_test_flag(hdev, HCI_CONFIG))
                memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
+
+       return rp->status;
 }
 
-static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_auth_enable(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_AUTH_ENABLE, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -441,26 +410,25 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
                mgmt_auth_enable_complete(hdev, rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_encrypt_mode(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        __u8 param;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_ENCRYPT_MODE, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
        if (!sent)
-               return;
+               return rp->status;
 
        param = *((__u8 *) sent);
 
@@ -468,23 +436,22 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
                set_bit(HCI_ENCRYPT, &hdev->flags);
        else
                clear_bit(HCI_ENCRYPT, &hdev->flags);
+
+       return rp->status;
 }
 
-static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_scan_enable(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        __u8 param;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SCAN_ENABLE, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
        if (!sent)
-               return;
+               return rp->status;
 
        param = *((__u8 *) sent);
 
@@ -507,26 +474,25 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
 done:
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_set_event_filter(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_set_event_filter(struct hci_dev *hdev, void *data,
+                                 struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_set_event_filter *cp;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SCAN_ENABLE, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_SET_EVENT_FLT);
        if (!sent)
-               return;
+               return rp->status;
 
        cp = (struct hci_cp_set_event_filter *)sent;
 
@@ -534,41 +500,39 @@ static void hci_cc_set_event_filter(struct hci_dev *hdev, struct sk_buff *skb)
                hci_dev_clear_flag(hdev, HCI_EVENT_FILTER_CONFIGURED);
        else
                hci_dev_set_flag(hdev, HCI_EVENT_FILTER_CONFIGURED);
+
+       return rp->status;
 }
 
-static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_class_of_dev(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_rp_read_class_of_dev *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_CLASS_OF_DEV, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_class_of_dev *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        memcpy(hdev->dev_class, rp->dev_class, 3);
 
        bt_dev_dbg(hdev, "class 0x%.2x%.2x%.2x", hdev->dev_class[2],
                   hdev->dev_class[1], hdev->dev_class[0]);
+
+       return rp->status;
 }
 
-static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_class_of_dev(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_CLASS_OF_DEV, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -579,26 +543,25 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
                mgmt_set_class_of_dev_complete(hdev, sent, rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_voice_setting(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_rp_read_voice_setting *rp;
+       struct hci_rp_read_voice_setting *rp = data;
        __u16 setting;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_VOICE_SETTING, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        setting = __le16_to_cpu(rp->voice_setting);
 
        if (hdev->voice_setting == setting)
-               return;
+               return rp->status;
 
        hdev->voice_setting = setting;
 
@@ -606,33 +569,30 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+
+       return rp->status;
 }
 
-static void hci_cc_write_voice_setting(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_write_voice_setting(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        __u16 setting;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_VOICE_SETTING,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
        if (!sent)
-               return;
+               return rp->status;
 
        setting = get_unaligned_le16(sent);
 
        if (hdev->voice_setting == setting)
-               return;
+               return rp->status;
 
        hdev->voice_setting = setting;
 
@@ -640,42 +600,38 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
 
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+
+       return rp->status;
 }
 
-static void hci_cc_read_num_supported_iac(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_read_num_supported_iac(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_read_num_supported_iac *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_NUM_SUPPORTED_IAC,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_num_supported_iac *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->num_iac = rp->num_iac;
 
        bt_dev_dbg(hdev, "num iac %d", hdev->num_iac);
+
+       return rp->status;
 }
 
-static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_ssp_mode(struct hci_dev *hdev, void *data,
+                               struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_write_ssp_mode *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SSP_MODE, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -694,22 +650,21 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_sc_support(struct hci_dev *hdev, void *data,
+                                 struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_write_sc_support *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SC_SUPPORT, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -728,20 +683,19 @@ static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_local_version(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_rp_read_local_version *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_VERSION, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_version *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (hci_dev_test_flag(hdev, HCI_SETUP) ||
            hci_dev_test_flag(hdev, HCI_CONFIG)) {
@@ -751,43 +705,37 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
                hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
                hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
        }
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_commands(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_read_local_commands(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_rp_read_local_commands *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_COMMANDS,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_commands *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (hci_dev_test_flag(hdev, HCI_SETUP) ||
            hci_dev_test_flag(hdev, HCI_CONFIG))
                memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
+
+       return rp->status;
 }
 
-static void hci_cc_read_auth_payload_timeout(struct hci_dev *hdev,
-                                            struct sk_buff *skb)
+static u8 hci_cc_read_auth_payload_timeout(struct hci_dev *hdev, void *data,
+                                          struct sk_buff *skb)
 {
-       struct hci_rp_read_auth_payload_to *rp;
+       struct hci_rp_read_auth_payload_to *rp = data;
        struct hci_conn *conn;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_AUTH_PAYLOAD_TO,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -796,27 +744,25 @@ static void hci_cc_read_auth_payload_timeout(struct hci_dev *hdev,
                conn->auth_payload_timeout = __le16_to_cpu(rp->timeout);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_write_auth_payload_timeout(struct hci_dev *hdev,
-                                             struct sk_buff *skb)
+static u8 hci_cc_write_auth_payload_timeout(struct hci_dev *hdev, void *data,
+                                           struct sk_buff *skb)
 {
-       struct hci_rp_write_auth_payload_to *rp;
+       struct hci_rp_write_auth_payload_to *rp = data;
        struct hci_conn *conn;
        void *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_AUTH_PAYLOAD_TO, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -825,22 +771,19 @@ static void hci_cc_write_auth_payload_timeout(struct hci_dev *hdev,
                conn->auth_payload_timeout = get_unaligned_le16(sent + 2);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_features(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_read_local_features(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_rp_read_local_features *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_FEATURES,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_features *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        memcpy(hdev->features, rp->features, 8);
 
@@ -880,60 +823,53 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
 
        if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
                hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_read_local_ext_features(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
-       struct hci_rp_read_local_ext_features *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_EXT_FEATURES,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_ext_features *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (hdev->max_page < rp->max_page)
                hdev->max_page = rp->max_page;
 
        if (rp->page < HCI_MAX_PAGES)
                memcpy(hdev->features[rp->page], rp->features, 8);
+
+       return rp->status;
 }
 
-static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_read_flow_control_mode(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_read_flow_control_mode *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_FLOW_CONTROL_MODE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_flow_control_mode *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->flow_ctl_mode = rp->mode;
+
+       return rp->status;
 }
 
-static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data,
+                                 struct sk_buff *skb)
 {
-       struct hci_rp_read_buffer_size *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_BUFFER_SIZE, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_buffer_size *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
        hdev->sco_mtu  = rp->sco_mtu;
@@ -950,149 +886,130 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
               hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
+
+       return rp->status;
 }
 
-static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_bd_addr(struct hci_dev *hdev, void *data,
+                             struct sk_buff *skb)
 {
-       struct hci_rp_read_bd_addr *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_BD_ADDR, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_bd_addr *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (test_bit(HCI_INIT, &hdev->flags))
                bacpy(&hdev->bdaddr, &rp->bdaddr);
 
        if (hci_dev_test_flag(hdev, HCI_SETUP))
                bacpy(&hdev->setup_addr, &rp->bdaddr);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_pairing_opts(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_read_local_pairing_opts(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
-       struct hci_rp_read_local_pairing_opts *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_PAIRING_OPTS,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_pairing_opts *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (hci_dev_test_flag(hdev, HCI_SETUP) ||
            hci_dev_test_flag(hdev, HCI_CONFIG)) {
                hdev->pairing_opts = rp->pairing_opts;
                hdev->max_enc_key_size = rp->max_key_size;
        }
+
+       return rp->status;
 }
 
-static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_read_page_scan_activity(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
-       struct hci_rp_read_page_scan_activity *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_PAGE_SCAN_ACTIVITY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_page_scan_activity *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (test_bit(HCI_INIT, &hdev->flags)) {
                hdev->page_scan_interval = __le16_to_cpu(rp->interval);
                hdev->page_scan_window = __le16_to_cpu(rp->window);
        }
+
+       return rp->status;
 }
 
-static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
-                                           struct sk_buff *skb)
+static u8 hci_cc_write_page_scan_activity(struct hci_dev *hdev, void *data,
+                                         struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_write_page_scan_activity *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_PAGE_SCAN_ACTIVITY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY);
        if (!sent)
-               return;
+               return rp->status;
 
        hdev->page_scan_interval = __le16_to_cpu(sent->interval);
        hdev->page_scan_window = __le16_to_cpu(sent->window);
+
+       return rp->status;
 }
 
-static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_read_page_scan_type(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_rp_read_page_scan_type *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_PAGE_SCAN_TYPE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_page_scan_type *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (test_bit(HCI_INIT, &hdev->flags))
                hdev->page_scan_type = rp->type;
+
+       return rp->status;
 }
 
-static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_write_page_scan_type(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        u8 *type;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_PAGE_SCAN_TYPE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        type = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE);
        if (type)
                hdev->page_scan_type = *type;
+
+       return rp->status;
 }
 
-static void hci_cc_read_data_block_size(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_read_data_block_size(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_rp_read_data_block_size *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_DATA_BLOCK_SIZE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_data_block_size *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
        hdev->block_len = __le16_to_cpu(rp->block_len);
@@ -1102,24 +1019,21 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
 
        BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
               hdev->block_cnt, hdev->block_len);
+
+       return rp->status;
 }
 
-static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data,
+                           struct sk_buff *skb)
 {
-       struct hci_rp_read_clock *rp;
+       struct hci_rp_read_clock *rp = data;
        struct hci_cp_read_clock *cp;
        struct hci_conn *conn;
 
-       BT_DBG("%s", hdev->name);
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_CLOCK, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1140,22 +1054,18 @@ static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
 
 unlock:
        hci_dev_unlock(hdev);
+       return rp->status;
 }
 
-static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_read_local_amp_info(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_rp_read_local_amp_info *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_AMP_INFO,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_amp_info *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->amp_status = rp->amp_status;
        hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
@@ -1167,77 +1077,67 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
        hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
        hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
+
+       return rp->status;
 }
 
-static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
-       struct hci_rp_read_inq_rsp_tx_power *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_INQ_RSP_TX_POWER,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_inq_rsp_tx_power *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->inq_tx_power = rp->tx_power;
+
+       return rp->status;
 }
 
-static void hci_cc_read_def_err_data_reporting(struct hci_dev *hdev,
-                                              struct sk_buff *skb)
+static u8 hci_cc_read_def_err_data_reporting(struct hci_dev *hdev, void *data,
+                                            struct sk_buff *skb)
 {
-       struct hci_rp_read_def_err_data_reporting *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_DEF_ERR_DATA_REPORTING,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_def_err_data_reporting *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->err_data_reporting = rp->err_data_reporting;
+
+       return rp->status;
 }
 
-static void hci_cc_write_def_err_data_reporting(struct hci_dev *hdev,
-                                               struct sk_buff *skb)
+static u8 hci_cc_write_def_err_data_reporting(struct hci_dev *hdev, void *data,
+                                             struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_write_def_err_data_reporting *cp;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING);
        if (!cp)
-               return;
+               return rp->status;
 
        hdev->err_data_reporting = cp->err_data_reporting;
+
+       return rp->status;
 }
 
-static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_pin_code_reply(struct hci_dev *hdev, void *data,
+                               struct sk_buff *skb)
 {
-       struct hci_rp_pin_code_reply *rp;
+       struct hci_rp_pin_code_reply *rp = data;
        struct hci_cp_pin_code_reply *cp;
        struct hci_conn *conn;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_PIN_CODE_REPLY, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        hci_dev_lock(hdev);
@@ -1258,15 +1158,13 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 unlock:
        hci_dev_unlock(hdev);
+       return rp->status;
 }
 
-static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_pin_code_neg_reply(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_rp_pin_code_neg_reply *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_pin_code_neg_reply *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
@@ -1277,22 +1175,19 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
                                                 rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_le_read_buffer_size(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_rp_le_read_buffer_size *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_BUFFER_SIZE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_buffer_size *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
        hdev->le_pkts = rp->le_max_pkt;
@@ -1300,51 +1195,44 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
        hdev->le_cnt = hdev->le_pkts;
 
        BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_local_features(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_le_read_local_features(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_le_read_local_features *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_LOCAL_FEATURES,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_local_features *rp = data;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        memcpy(hdev->le_features, rp->features, 8);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_rp_le_read_adv_tx_power *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_ADV_TX_POWER,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_adv_tx_power *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->adv_tx_power = rp->tx_power;
+
+       return rp->status;
 }
 
-static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_user_confirm_reply(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_rp_user_confirm_reply *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_CONFIRM_REPLY, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_user_confirm_reply *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
@@ -1355,17 +1243,14 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
                                                 rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_user_confirm_reply *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_CONFIRM_NEG_REPLY,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_user_confirm_reply *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
@@ -1376,15 +1261,14 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
                                                     ACL_LINK, 0, rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_user_passkey_reply(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_rp_user_confirm_reply *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_PASSKEY_REPLY, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_user_confirm_reply *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
@@ -1395,16 +1279,14 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
                                                 0, rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_user_confirm_reply *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_PASSKEY_NEG_REPLY, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_user_confirm_reply *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
@@ -1415,49 +1297,44 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
                                                     ACL_LINK, 0, rp->status);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_read_local_oob_data(struct hci_dev *hdev, void *data,
+                                    struct sk_buff *skb)
 {
-       struct hci_rp_read_local_oob_data *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_OOB_DATA, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_oob_data *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
+
+       return rp->status;
 }
 
-static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
-       struct hci_rp_read_local_oob_ext_data *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_OOB_EXT_DATA, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_read_local_oob_ext_data *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_le_set_random_addr(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        bdaddr_t *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_RANDOM_ADDR, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1470,25 +1347,24 @@ static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_le_set_default_phy(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_le_set_default_phy *cp;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_DEFAULT_PHY);
        if (!cp)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1496,24 +1372,21 @@ static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
        hdev->le_rx_def_phys = cp->rx_phys;
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
-                                              struct sk_buff *skb)
+static u8 hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev, void *data,
+                                           struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_le_set_adv_set_rand_addr *cp;
        struct adv_info *adv;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_SET_RAND_ADDR);
        /* Update only in case the adv instance since handle 0x00 shall be using
@@ -1521,7 +1394,7 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
         * non-extended adverting.
         */
        if (!cp || !cp->handle)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1537,26 +1410,25 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
        }
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_remove_adv_set(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_le_remove_adv_set(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        u8 *instance;
        int err;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_REMOVE_ADV_SET, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        instance = hci_sent_cmd_data(hdev, HCI_OP_LE_REMOVE_ADV_SET);
        if (!instance)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1566,25 +1438,24 @@ static void hci_cc_le_remove_adv_set(struct hci_dev *hdev, struct sk_buff *skb)
                                         *instance);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_clear_adv_sets(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_le_clear_adv_sets(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct adv_info *adv, *n;
        int err;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_CLEAR_ADV_SETS, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        if (!hci_sent_cmd_data(hdev, HCI_OP_LE_CLEAR_ADV_SETS))
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1598,44 +1469,40 @@ static void hci_cc_le_clear_adv_sets(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_transmit_power(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_le_read_transmit_power(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
-       struct hci_rp_le_read_transmit_power *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_TRANSMIT_POWER,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_transmit_power *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->min_le_tx_power = rp->min_le_tx_power;
        hdev->max_le_tx_power = rp->max_le_tx_power;
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_le_set_adv_enable(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        __u8 *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADV_ENABLE, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -1657,29 +1524,26 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
        struct hci_cp_le_set_ext_adv_enable *cp;
        struct hci_cp_ext_adv_set *set;
        struct adv_info *adv = NULL, *n;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_ADV_ENABLE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE);
        if (!cp)
-               return;
+               return rp->status;
 
        set = (void *)cp->data;
 
@@ -1726,53 +1590,48 @@ static void hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev,
 
 unlock:
        hci_dev_unlock(hdev);
+       return rp->status;
 }
 
-static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_le_set_scan_param(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
        struct hci_cp_le_set_scan_param *cp;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_SCAN_PARAM, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM);
        if (!cp)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
        hdev->le_scan_type = cp->type;
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_ext_scan_param(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_le_set_ext_scan_param(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
        struct hci_cp_le_set_ext_scan_params *cp;
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        struct hci_cp_le_scan_phy_params *phy_param;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_SCAN_PARAMS,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS);
        if (!cp)
-               return;
+               return rp->status;
 
        phy_param = (void *)cp->data;
 
@@ -1781,6 +1640,8 @@ static void hci_cc_le_set_ext_scan_param(struct hci_dev *hdev,
        hdev->le_scan_type = phy_param->type;
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
 static bool has_pending_adv_report(struct hci_dev *hdev)
@@ -1866,320 +1727,273 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
-                                     struct sk_buff *skb)
+static u8 hci_cc_le_set_scan_enable(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
 {
        struct hci_cp_le_set_scan_enable *cp;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_SCAN_ENABLE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
        if (!cp)
-               return;
+               return rp->status;
 
        le_set_scan_enable_complete(hdev, cp->enable);
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_ext_scan_enable(struct hci_dev *hdev,
-                                     struct sk_buff *skb)
+static u8 hci_cc_le_set_ext_scan_enable(struct hci_dev *hdev, void *data,
+                                       struct sk_buff *skb)
 {
        struct hci_cp_le_set_ext_scan_enable *cp;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_SCAN_ENABLE);
        if (!cp)
-               return;
+               return rp->status;
 
        le_set_scan_enable_complete(hdev, cp->enable);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_num_adv_sets(struct hci_dev *hdev,
+static u8 hci_cc_le_read_num_adv_sets(struct hci_dev *hdev, void *data,
                                      struct sk_buff *skb)
 {
-       struct hci_rp_le_read_num_supported_adv_sets *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_num_supported_adv_sets *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x No of Adv sets %u", rp->status,
                   rp->num_of_sets);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->le_num_of_adv_sets = rp->num_of_sets;
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_accept_list_size(struct hci_dev *hdev,
-                                           struct sk_buff *skb)
+static u8 hci_cc_le_read_accept_list_size(struct hci_dev *hdev, void *data,
+                                         struct sk_buff *skb)
 {
-       struct hci_rp_le_read_accept_list_size *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_ACCEPT_LIST_SIZE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_accept_list_size *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x size %u", rp->status, rp->size);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->le_accept_list_size = rp->size;
+
+       return rp->status;
 }
 
-static void hci_cc_le_clear_accept_list(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_le_clear_accept_list(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_CLEAR_ACCEPT_LIST,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_bdaddr_list_clear(&hdev->le_accept_list);
+
+       return rp->status;
 }
 
-static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_le_add_to_accept_list(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
        struct hci_cp_le_add_to_accept_list *sent;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_ADD_TO_ACCEPT_LIST,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_ACCEPT_LIST);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_bdaddr_list_add(&hdev->le_accept_list, &sent->bdaddr,
                            sent->bdaddr_type);
+
+       return rp->status;
 }
 
-static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_le_del_from_accept_list(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
        struct hci_cp_le_del_from_accept_list *sent;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_DEL_FROM_ACCEPT_LIST,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_ACCEPT_LIST);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_bdaddr_list_del(&hdev->le_accept_list, &sent->bdaddr,
                            sent->bdaddr_type);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
-                                           struct sk_buff *skb)
+static u8 hci_cc_le_read_supported_states(struct hci_dev *hdev, void *data,
+                                         struct sk_buff *skb)
 {
-       struct hci_rp_le_read_supported_states *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_SUPPORTED_STATES,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_supported_states *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        memcpy(hdev->le_states, rp->le_states, 8);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_def_data_len(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_le_read_def_data_len(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_rp_le_read_def_data_len *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_DEF_DATA_LEN,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_def_data_len *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->le_def_tx_len = le16_to_cpu(rp->tx_len);
        hdev->le_def_tx_time = le16_to_cpu(rp->tx_time);
+
+       return rp->status;
 }
 
-static void hci_cc_le_write_def_data_len(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_le_write_def_data_len(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
        struct hci_cp_le_write_def_data_len *sent;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_WRITE_DEF_DATA_LEN,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN);
        if (!sent)
-               return;
+               return rp->status;
 
        hdev->le_def_tx_len = le16_to_cpu(sent->tx_len);
        hdev->le_def_tx_time = le16_to_cpu(sent->tx_time);
+
+       return rp->status;
 }
 
-static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
-                                        struct sk_buff *skb)
+static u8 hci_cc_le_add_to_resolv_list(struct hci_dev *hdev, void *data,
+                                      struct sk_buff *skb)
 {
        struct hci_cp_le_add_to_resolv_list *sent;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_ADD_TO_RESOLV_LIST,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
                                sent->bdaddr_type, sent->peer_irk,
                                sent->local_irk);
+
+       return rp->status;
 }
 
-static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
+static u8 hci_cc_le_del_from_resolv_list(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
        struct hci_cp_le_del_from_resolv_list *sent;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_DEL_FROM_RESOLV_LIST,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
                            sent->bdaddr_type);
+
+       return rp->status;
 }
 
-static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
-                                      struct sk_buff *skb)
+static u8 hci_cc_le_clear_resolv_list(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_CLEAR_RESOLV_LIST,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_bdaddr_list_clear(&hdev->le_resolv_list);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_le_read_resolv_list_size(struct hci_dev *hdev, void *data,
+                                         struct sk_buff *skb)
 {
-       struct hci_rp_le_read_resolv_list_size *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_RESOLV_LIST_SIZE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_resolv_list_size *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x size %u", rp->status, rp->size);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->le_resolv_list_size = rp->size;
+
+       return rp->status;
 }
 
-static void hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev,
-                                               struct sk_buff *skb)
+static u8 hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev, void *data,
+                                              struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        __u8 *sent;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -2189,48 +2003,42 @@ static void hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev,
                hci_dev_clear_flag(hdev, HCI_LL_RPA_RESOLUTION);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_le_read_max_data_len(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+static u8 hci_cc_le_read_max_data_len(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_rp_le_read_max_data_len *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_MAX_DATA_LEN,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_rp_le_read_max_data_len *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hdev->le_max_tx_len = le16_to_cpu(rp->tx_len);
        hdev->le_max_tx_time = le16_to_cpu(rp->tx_time);
        hdev->le_max_rx_len = le16_to_cpu(rp->rx_len);
        hdev->le_max_rx_time = le16_to_cpu(rp->rx_time);
+
+       return rp->status;
 }
 
-static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static u8 hci_cc_write_le_host_supported(struct hci_dev *hdev, void *data,
+                                        struct sk_buff *skb)
 {
        struct hci_cp_write_le_host_supported *sent;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_LE_HOST_SUPPORTED,
-                            sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -2249,50 +2057,47 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
                hdev->features[1][0] &= ~LMP_HOST_LE_BREDR;
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_set_adv_param(struct hci_dev *hdev, void *data,
+                              struct sk_buff *skb)
 {
        struct hci_cp_le_set_adv_param *cp;
-       struct hci_ev_status *rp;
-
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADV_PARAM, sizeof(*rp));
-       if (!rp)
-               return;
+       struct hci_ev_status *rp = data;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
        if (!cp)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
        hdev->adv_addr_type = cp->own_address_type;
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_set_ext_adv_param(struct hci_dev *hdev, void *data,
+                                  struct sk_buff *skb)
 {
-       struct hci_rp_le_set_ext_adv_params *rp;
+       struct hci_rp_le_set_ext_adv_params *rp = data;
        struct hci_cp_le_set_ext_adv_params *cp;
        struct adv_info *adv_instance;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_ADV_PARAMS,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS);
        if (!cp)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
        hdev->adv_addr_type = cp->own_addr_type;
@@ -2308,21 +2113,20 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_update_adv_data(hdev, cp->handle);
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data,
+                          struct sk_buff *skb)
 {
-       struct hci_rp_read_rssi *rp;
+       struct hci_rp_read_rssi *rp = data;
        struct hci_conn *conn;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_RSSI, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -2331,26 +2135,25 @@ static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
                conn->rssi = rp->rssi;
 
        hci_dev_unlock(hdev);
+
+       return rp->status;
 }
 
-static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_read_tx_power(struct hci_dev *hdev, void *data,
+                              struct sk_buff *skb)
 {
        struct hci_cp_read_tx_power *sent;
-       struct hci_rp_read_tx_power *rp;
+       struct hci_rp_read_tx_power *rp = data;
        struct hci_conn *conn;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_TX_POWER, sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        sent = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
        if (!sent)
-               return;
+               return rp->status;
 
        hci_dev_lock(hdev);
 
@@ -2369,26 +2172,25 @@ static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)
 
 unlock:
        hci_dev_unlock(hdev);
+       return rp->status;
 }
 
-static void hci_cc_write_ssp_debug_mode(struct hci_dev *hdev, struct sk_buff *skb)
+static u8 hci_cc_write_ssp_debug_mode(struct hci_dev *hdev, void *data,
+                                     struct sk_buff *skb)
 {
-       struct hci_ev_status *rp;
+       struct hci_ev_status *rp = data;
        u8 *mode;
 
-       rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SSP_DEBUG_MODE,
-                            sizeof(*rp));
-       if (!rp)
-               return;
-
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
        if (rp->status)
-               return;
+               return rp->status;
 
        mode = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE);
        if (mode)
                hdev->ssp_debug_mode = *mode;
+
+       return rp->status;
 }
 
 static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
@@ -3909,372 +3711,226 @@ static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev, u8 ncmd)
        }
 }
 
-static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
-                                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_cmd_complete *ev = data;
-
-       *opcode = __le16_to_cpu(ev->opcode);
-       *status = skb->data[0];
-
-       switch (*opcode) {
-       case HCI_OP_INQUIRY_CANCEL:
-               hci_cc_inquiry_cancel(hdev, skb, status);
-               break;
-
-       case HCI_OP_PERIODIC_INQ:
-               hci_cc_periodic_inq(hdev, skb);
-               break;
-
-       case HCI_OP_EXIT_PERIODIC_INQ:
-               hci_cc_exit_periodic_inq(hdev, skb);
-               break;
-
-       case HCI_OP_REMOTE_NAME_REQ_CANCEL:
-               hci_cc_remote_name_req_cancel(hdev, skb);
-               break;
-
-       case HCI_OP_ROLE_DISCOVERY:
-               hci_cc_role_discovery(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LINK_POLICY:
-               hci_cc_read_link_policy(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_LINK_POLICY:
-               hci_cc_write_link_policy(hdev, skb);
-               break;
-
-       case HCI_OP_READ_DEF_LINK_POLICY:
-               hci_cc_read_def_link_policy(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_DEF_LINK_POLICY:
-               hci_cc_write_def_link_policy(hdev, skb);
-               break;
-
-       case HCI_OP_RESET:
-               hci_cc_reset(hdev, skb);
-               break;
-
-       case HCI_OP_READ_STORED_LINK_KEY:
-               hci_cc_read_stored_link_key(hdev, skb);
-               break;
-
-       case HCI_OP_DELETE_STORED_LINK_KEY:
-               hci_cc_delete_stored_link_key(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_LOCAL_NAME:
-               hci_cc_write_local_name(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_NAME:
-               hci_cc_read_local_name(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_AUTH_ENABLE:
-               hci_cc_write_auth_enable(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_ENCRYPT_MODE:
-               hci_cc_write_encrypt_mode(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_SCAN_ENABLE:
-               hci_cc_write_scan_enable(hdev, skb);
-               break;
-
-       case HCI_OP_SET_EVENT_FLT:
-               hci_cc_set_event_filter(hdev, skb);
-               break;
-
-       case HCI_OP_READ_CLASS_OF_DEV:
-               hci_cc_read_class_of_dev(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_CLASS_OF_DEV:
-               hci_cc_write_class_of_dev(hdev, skb);
-               break;
-
-       case HCI_OP_READ_VOICE_SETTING:
-               hci_cc_read_voice_setting(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_VOICE_SETTING:
-               hci_cc_write_voice_setting(hdev, skb);
-               break;
-
-       case HCI_OP_READ_NUM_SUPPORTED_IAC:
-               hci_cc_read_num_supported_iac(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_SSP_MODE:
-               hci_cc_write_ssp_mode(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_SC_SUPPORT:
-               hci_cc_write_sc_support(hdev, skb);
-               break;
-
-       case HCI_OP_READ_AUTH_PAYLOAD_TO:
-               hci_cc_read_auth_payload_timeout(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_AUTH_PAYLOAD_TO:
-               hci_cc_write_auth_payload_timeout(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_VERSION:
-               hci_cc_read_local_version(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_COMMANDS:
-               hci_cc_read_local_commands(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_FEATURES:
-               hci_cc_read_local_features(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_EXT_FEATURES:
-               hci_cc_read_local_ext_features(hdev, skb);
-               break;
-
-       case HCI_OP_READ_BUFFER_SIZE:
-               hci_cc_read_buffer_size(hdev, skb);
-               break;
-
-       case HCI_OP_READ_BD_ADDR:
-               hci_cc_read_bd_addr(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_PAIRING_OPTS:
-               hci_cc_read_local_pairing_opts(hdev, skb);
-               break;
-
-       case HCI_OP_READ_PAGE_SCAN_ACTIVITY:
-               hci_cc_read_page_scan_activity(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_PAGE_SCAN_ACTIVITY:
-               hci_cc_write_page_scan_activity(hdev, skb);
-               break;
-
-       case HCI_OP_READ_PAGE_SCAN_TYPE:
-               hci_cc_read_page_scan_type(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_PAGE_SCAN_TYPE:
-               hci_cc_write_page_scan_type(hdev, skb);
-               break;
-
-       case HCI_OP_READ_DATA_BLOCK_SIZE:
-               hci_cc_read_data_block_size(hdev, skb);
-               break;
-
-       case HCI_OP_READ_FLOW_CONTROL_MODE:
-               hci_cc_read_flow_control_mode(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_AMP_INFO:
-               hci_cc_read_local_amp_info(hdev, skb);
-               break;
-
-       case HCI_OP_READ_CLOCK:
-               hci_cc_read_clock(hdev, skb);
-               break;
-
-       case HCI_OP_READ_INQ_RSP_TX_POWER:
-               hci_cc_read_inq_rsp_tx_power(hdev, skb);
-               break;
-
-       case HCI_OP_READ_DEF_ERR_DATA_REPORTING:
-               hci_cc_read_def_err_data_reporting(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_DEF_ERR_DATA_REPORTING:
-               hci_cc_write_def_err_data_reporting(hdev, skb);
-               break;
-
-       case HCI_OP_PIN_CODE_REPLY:
-               hci_cc_pin_code_reply(hdev, skb);
-               break;
-
-       case HCI_OP_PIN_CODE_NEG_REPLY:
-               hci_cc_pin_code_neg_reply(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_OOB_DATA:
-               hci_cc_read_local_oob_data(hdev, skb);
-               break;
-
-       case HCI_OP_READ_LOCAL_OOB_EXT_DATA:
-               hci_cc_read_local_oob_ext_data(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_BUFFER_SIZE:
-               hci_cc_le_read_buffer_size(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_LOCAL_FEATURES:
-               hci_cc_le_read_local_features(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_ADV_TX_POWER:
-               hci_cc_le_read_adv_tx_power(hdev, skb);
-               break;
-
-       case HCI_OP_USER_CONFIRM_REPLY:
-               hci_cc_user_confirm_reply(hdev, skb);
-               break;
-
-       case HCI_OP_USER_CONFIRM_NEG_REPLY:
-               hci_cc_user_confirm_neg_reply(hdev, skb);
-               break;
-
-       case HCI_OP_USER_PASSKEY_REPLY:
-               hci_cc_user_passkey_reply(hdev, skb);
-               break;
-
-       case HCI_OP_USER_PASSKEY_NEG_REPLY:
-               hci_cc_user_passkey_neg_reply(hdev, skb);
-               break;
-
-       case HCI_OP_LE_SET_RANDOM_ADDR:
-               hci_cc_le_set_random_addr(hdev, skb);
-               break;
-
-       case HCI_OP_LE_SET_ADV_ENABLE:
-               hci_cc_le_set_adv_enable(hdev, skb);
-               break;
-
-       case HCI_OP_LE_SET_SCAN_PARAM:
-               hci_cc_le_set_scan_param(hdev, skb);
-               break;
-
-       case HCI_OP_LE_SET_SCAN_ENABLE:
-               hci_cc_le_set_scan_enable(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_ACCEPT_LIST_SIZE:
-               hci_cc_le_read_accept_list_size(hdev, skb);
-               break;
-
-       case HCI_OP_LE_CLEAR_ACCEPT_LIST:
-               hci_cc_le_clear_accept_list(hdev, skb);
-               break;
-
-       case HCI_OP_LE_ADD_TO_ACCEPT_LIST:
-               hci_cc_le_add_to_accept_list(hdev, skb);
-               break;
-
-       case HCI_OP_LE_DEL_FROM_ACCEPT_LIST:
-               hci_cc_le_del_from_accept_list(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_SUPPORTED_STATES:
-               hci_cc_le_read_supported_states(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_DEF_DATA_LEN:
-               hci_cc_le_read_def_data_len(hdev, skb);
-               break;
-
-       case HCI_OP_LE_WRITE_DEF_DATA_LEN:
-               hci_cc_le_write_def_data_len(hdev, skb);
-               break;
-
-       case HCI_OP_LE_ADD_TO_RESOLV_LIST:
-               hci_cc_le_add_to_resolv_list(hdev, skb);
-               break;
-
-       case HCI_OP_LE_DEL_FROM_RESOLV_LIST:
-               hci_cc_le_del_from_resolv_list(hdev, skb);
-               break;
-
-       case HCI_OP_LE_CLEAR_RESOLV_LIST:
-               hci_cc_le_clear_resolv_list(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_RESOLV_LIST_SIZE:
-               hci_cc_le_read_resolv_list_size(hdev, skb);
-               break;
-
-       case HCI_OP_LE_SET_ADDR_RESOLV_ENABLE:
-               hci_cc_le_set_addr_resolution_enable(hdev, skb);
-               break;
-
-       case HCI_OP_LE_READ_MAX_DATA_LEN:
-               hci_cc_le_read_max_data_len(hdev, skb);
-               break;
-
-       case HCI_OP_WRITE_LE_HOST_SUPPORTED:
-               hci_cc_write_le_host_supported(hdev, skb);
-               break;
-
-       case HCI_OP_LE_SET_ADV_PARAM:
-               hci_cc_set_adv_param(hdev, skb);
-               break;
-
-       case HCI_OP_READ_RSSI:
-               hci_cc_read_rssi(hdev, skb);
-               break;
-
-       case HCI_OP_READ_TX_POWER:
-               hci_cc_read_tx_power(hdev, skb);
-               break;
+#define HCI_CC_VL(_op, _func, _min, _max) \
+{ \
+       .op = _op, \
+       .func = _func, \
+       .min_len = _min, \
+       .max_len = _max, \
+}
 
-       case HCI_OP_WRITE_SSP_DEBUG_MODE:
-               hci_cc_write_ssp_debug_mode(hdev, skb);
-               break;
+#define HCI_CC(_op, _func, _len) \
+       HCI_CC_VL(_op, _func, _len, _len)
 
-       case HCI_OP_LE_SET_EXT_SCAN_PARAMS:
-               hci_cc_le_set_ext_scan_param(hdev, skb);
-               break;
+#define HCI_CC_STATUS(_op, _func) \
+       HCI_CC(_op, _func, sizeof(struct hci_ev_status))
 
-       case HCI_OP_LE_SET_EXT_SCAN_ENABLE:
-               hci_cc_le_set_ext_scan_enable(hdev, skb);
-               break;
+static const struct hci_cc {
+       u16  op;
+       u8 (*func)(struct hci_dev *hdev, void *data, struct sk_buff *skb);
+       u16  min_len;
+       u16  max_len;
+} hci_cc_table[] = {
+       HCI_CC_STATUS(HCI_OP_INQUIRY_CANCEL, hci_cc_inquiry_cancel),
+       HCI_CC_STATUS(HCI_OP_PERIODIC_INQ, hci_cc_periodic_inq),
+       HCI_CC_STATUS(HCI_OP_EXIT_PERIODIC_INQ, hci_cc_exit_periodic_inq),
+       HCI_CC_STATUS(HCI_OP_REMOTE_NAME_REQ_CANCEL,
+                     hci_cc_remote_name_req_cancel),
+       HCI_CC(HCI_OP_ROLE_DISCOVERY, hci_cc_role_discovery,
+              sizeof(struct hci_rp_role_discovery)),
+       HCI_CC(HCI_OP_READ_LINK_POLICY, hci_cc_read_link_policy,
+              sizeof(struct hci_rp_read_link_policy)),
+       HCI_CC(HCI_OP_WRITE_LINK_POLICY, hci_cc_write_link_policy,
+              sizeof(struct hci_rp_write_link_policy)),
+       HCI_CC(HCI_OP_READ_DEF_LINK_POLICY, hci_cc_read_def_link_policy,
+              sizeof(struct hci_rp_read_def_link_policy)),
+       HCI_CC_STATUS(HCI_OP_WRITE_DEF_LINK_POLICY,
+                     hci_cc_write_def_link_policy),
+       HCI_CC_STATUS(HCI_OP_RESET, hci_cc_reset),
+       HCI_CC(HCI_OP_READ_STORED_LINK_KEY, hci_cc_read_stored_link_key,
+              sizeof(struct hci_rp_read_stored_link_key)),
+       HCI_CC(HCI_OP_DELETE_STORED_LINK_KEY, hci_cc_delete_stored_link_key,
+              sizeof(struct hci_rp_delete_stored_link_key)),
+       HCI_CC_STATUS(HCI_OP_WRITE_LOCAL_NAME, hci_cc_write_local_name),
+       HCI_CC(HCI_OP_READ_LOCAL_NAME, hci_cc_read_local_name,
+              sizeof(struct hci_rp_read_local_name)),
+       HCI_CC_STATUS(HCI_OP_WRITE_AUTH_ENABLE, hci_cc_write_auth_enable),
+       HCI_CC_STATUS(HCI_OP_WRITE_ENCRYPT_MODE, hci_cc_write_encrypt_mode),
+       HCI_CC_STATUS(HCI_OP_WRITE_SCAN_ENABLE, hci_cc_write_scan_enable),
+       HCI_CC_STATUS(HCI_OP_SET_EVENT_FLT, hci_cc_set_event_filter),
+       HCI_CC(HCI_OP_READ_CLASS_OF_DEV, hci_cc_read_class_of_dev,
+              sizeof(struct hci_rp_read_class_of_dev)),
+       HCI_CC_STATUS(HCI_OP_WRITE_CLASS_OF_DEV, hci_cc_write_class_of_dev),
+       HCI_CC(HCI_OP_READ_VOICE_SETTING, hci_cc_read_voice_setting,
+              sizeof(struct hci_rp_read_voice_setting)),
+       HCI_CC_STATUS(HCI_OP_WRITE_VOICE_SETTING, hci_cc_write_voice_setting),
+       HCI_CC(HCI_OP_READ_NUM_SUPPORTED_IAC, hci_cc_read_num_supported_iac,
+              sizeof(struct hci_rp_read_num_supported_iac)),
+       HCI_CC_STATUS(HCI_OP_WRITE_SSP_MODE, hci_cc_write_ssp_mode),
+       HCI_CC_STATUS(HCI_OP_WRITE_SC_SUPPORT, hci_cc_write_sc_support),
+       HCI_CC(HCI_OP_READ_AUTH_PAYLOAD_TO, hci_cc_read_auth_payload_timeout,
+              sizeof(struct hci_rp_read_auth_payload_to)),
+       HCI_CC(HCI_OP_WRITE_AUTH_PAYLOAD_TO, hci_cc_write_auth_payload_timeout,
+              sizeof(struct hci_rp_write_auth_payload_to)),
+       HCI_CC(HCI_OP_READ_LOCAL_VERSION, hci_cc_read_local_version,
+              sizeof(struct hci_rp_read_local_version)),
+       HCI_CC(HCI_OP_READ_LOCAL_COMMANDS, hci_cc_read_local_commands,
+              sizeof(struct hci_rp_read_local_commands)),
+       HCI_CC(HCI_OP_READ_LOCAL_FEATURES, hci_cc_read_local_features,
+              sizeof(struct hci_rp_read_local_features)),
+       HCI_CC(HCI_OP_READ_LOCAL_EXT_FEATURES, hci_cc_read_local_ext_features,
+              sizeof(struct hci_rp_read_local_ext_features)),
+       HCI_CC(HCI_OP_READ_BUFFER_SIZE, hci_cc_read_buffer_size,
+              sizeof(struct hci_rp_read_buffer_size)),
+       HCI_CC(HCI_OP_READ_BD_ADDR, hci_cc_read_bd_addr,
+              sizeof(struct hci_rp_read_bd_addr)),
+       HCI_CC(HCI_OP_READ_LOCAL_PAIRING_OPTS, hci_cc_read_local_pairing_opts,
+              sizeof(struct hci_rp_read_local_pairing_opts)),
+       HCI_CC(HCI_OP_READ_PAGE_SCAN_ACTIVITY, hci_cc_read_page_scan_activity,
+              sizeof(struct hci_rp_read_page_scan_activity)),
+       HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
+                     hci_cc_write_page_scan_activity),
+       HCI_CC(HCI_OP_READ_PAGE_SCAN_TYPE, hci_cc_read_page_scan_type,
+              sizeof(struct hci_rp_read_page_scan_type)),
+       HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_TYPE, hci_cc_write_page_scan_type),
+       HCI_CC(HCI_OP_READ_DATA_BLOCK_SIZE, hci_cc_read_data_block_size,
+              sizeof(struct hci_rp_read_data_block_size)),
+       HCI_CC(HCI_OP_READ_FLOW_CONTROL_MODE, hci_cc_read_flow_control_mode,
+              sizeof(struct hci_rp_read_flow_control_mode)),
+       HCI_CC(HCI_OP_READ_LOCAL_AMP_INFO, hci_cc_read_local_amp_info,
+              sizeof(struct hci_rp_read_local_amp_info)),
+       HCI_CC(HCI_OP_READ_CLOCK, hci_cc_read_clock,
+              sizeof(struct hci_rp_read_clock)),
+       HCI_CC(HCI_OP_READ_INQ_RSP_TX_POWER, hci_cc_read_inq_rsp_tx_power,
+              sizeof(struct hci_rp_read_inq_rsp_tx_power)),
+       HCI_CC(HCI_OP_READ_DEF_ERR_DATA_REPORTING,
+              hci_cc_read_def_err_data_reporting,
+              sizeof(struct hci_rp_read_def_err_data_reporting)),
+       HCI_CC_STATUS(HCI_OP_WRITE_DEF_ERR_DATA_REPORTING,
+                     hci_cc_write_def_err_data_reporting),
+       HCI_CC(HCI_OP_PIN_CODE_REPLY, hci_cc_pin_code_reply,
+              sizeof(struct hci_rp_pin_code_reply)),
+       HCI_CC(HCI_OP_PIN_CODE_NEG_REPLY, hci_cc_pin_code_neg_reply,
+              sizeof(struct hci_rp_pin_code_neg_reply)),
+       HCI_CC(HCI_OP_READ_LOCAL_OOB_DATA, hci_cc_read_local_oob_data,
+              sizeof(struct hci_rp_read_local_oob_data)),
+       HCI_CC(HCI_OP_READ_LOCAL_OOB_EXT_DATA, hci_cc_read_local_oob_ext_data,
+              sizeof(struct hci_rp_read_local_oob_ext_data)),
+       HCI_CC(HCI_OP_LE_READ_BUFFER_SIZE, hci_cc_le_read_buffer_size,
+              sizeof(struct hci_rp_le_read_buffer_size)),
+       HCI_CC(HCI_OP_LE_READ_LOCAL_FEATURES, hci_cc_le_read_local_features,
+              sizeof(struct hci_rp_le_read_local_features)),
+       HCI_CC(HCI_OP_LE_READ_ADV_TX_POWER, hci_cc_le_read_adv_tx_power,
+              sizeof(struct hci_rp_le_read_adv_tx_power)),
+       HCI_CC(HCI_OP_USER_CONFIRM_REPLY, hci_cc_user_confirm_reply,
+              sizeof(struct hci_rp_user_confirm_reply)),
+       HCI_CC(HCI_OP_USER_CONFIRM_NEG_REPLY, hci_cc_user_confirm_neg_reply,
+              sizeof(struct hci_rp_user_confirm_reply)),
+       HCI_CC(HCI_OP_USER_PASSKEY_REPLY, hci_cc_user_passkey_reply,
+              sizeof(struct hci_rp_user_confirm_reply)),
+       HCI_CC(HCI_OP_USER_PASSKEY_NEG_REPLY, hci_cc_user_passkey_neg_reply,
+              sizeof(struct hci_rp_user_confirm_reply)),
+       HCI_CC_STATUS(HCI_OP_LE_SET_RANDOM_ADDR, hci_cc_le_set_random_addr),
+       HCI_CC_STATUS(HCI_OP_LE_SET_ADV_ENABLE, hci_cc_le_set_adv_enable),
+       HCI_CC_STATUS(HCI_OP_LE_SET_SCAN_PARAM, hci_cc_le_set_scan_param),
+       HCI_CC_STATUS(HCI_OP_LE_SET_SCAN_ENABLE, hci_cc_le_set_scan_enable),
+       HCI_CC(HCI_OP_LE_READ_ACCEPT_LIST_SIZE,
+              hci_cc_le_read_accept_list_size,
+              sizeof(struct hci_rp_le_read_accept_list_size)),
+       HCI_CC_STATUS(HCI_OP_LE_CLEAR_ACCEPT_LIST, hci_cc_le_clear_accept_list),
+       HCI_CC_STATUS(HCI_OP_LE_ADD_TO_ACCEPT_LIST,
+                     hci_cc_le_add_to_accept_list),
+       HCI_CC_STATUS(HCI_OP_LE_DEL_FROM_ACCEPT_LIST,
+                     hci_cc_le_del_from_accept_list),
+       HCI_CC(HCI_OP_LE_READ_SUPPORTED_STATES, hci_cc_le_read_supported_states,
+              sizeof(struct hci_rp_le_read_supported_states)),
+       HCI_CC(HCI_OP_LE_READ_DEF_DATA_LEN, hci_cc_le_read_def_data_len,
+              sizeof(struct hci_rp_le_read_def_data_len)),
+       HCI_CC_STATUS(HCI_OP_LE_WRITE_DEF_DATA_LEN,
+                     hci_cc_le_write_def_data_len),
+       HCI_CC_STATUS(HCI_OP_LE_ADD_TO_RESOLV_LIST,
+                     hci_cc_le_add_to_resolv_list),
+       HCI_CC_STATUS(HCI_OP_LE_DEL_FROM_RESOLV_LIST,
+                     hci_cc_le_del_from_resolv_list),
+       HCI_CC_STATUS(HCI_OP_LE_CLEAR_RESOLV_LIST,
+                     hci_cc_le_clear_resolv_list),
+       HCI_CC(HCI_OP_LE_READ_RESOLV_LIST_SIZE, hci_cc_le_read_resolv_list_size,
+              sizeof(struct hci_rp_le_read_resolv_list_size)),
+       HCI_CC_STATUS(HCI_OP_LE_SET_ADDR_RESOLV_ENABLE,
+                     hci_cc_le_set_addr_resolution_enable),
+       HCI_CC(HCI_OP_LE_READ_MAX_DATA_LEN, hci_cc_le_read_max_data_len,
+              sizeof(struct hci_rp_le_read_max_data_len)),
+       HCI_CC_STATUS(HCI_OP_WRITE_LE_HOST_SUPPORTED,
+                     hci_cc_write_le_host_supported),
+       HCI_CC_STATUS(HCI_OP_LE_SET_ADV_PARAM, hci_cc_set_adv_param),
+       HCI_CC(HCI_OP_READ_RSSI, hci_cc_read_rssi,
+              sizeof(struct hci_rp_read_rssi)),
+       HCI_CC(HCI_OP_READ_TX_POWER, hci_cc_read_tx_power,
+              sizeof(struct hci_rp_read_tx_power)),
+       HCI_CC_STATUS(HCI_OP_WRITE_SSP_DEBUG_MODE, hci_cc_write_ssp_debug_mode),
+       HCI_CC_STATUS(HCI_OP_LE_SET_EXT_SCAN_PARAMS,
+                     hci_cc_le_set_ext_scan_param),
+       HCI_CC_STATUS(HCI_OP_LE_SET_EXT_SCAN_ENABLE,
+                     hci_cc_le_set_ext_scan_enable),
+       HCI_CC_STATUS(HCI_OP_LE_SET_DEFAULT_PHY, hci_cc_le_set_default_phy),
+       HCI_CC(HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
+              hci_cc_le_read_num_adv_sets,
+              sizeof(struct hci_rp_le_read_num_supported_adv_sets)),
+       HCI_CC(HCI_OP_LE_SET_EXT_ADV_PARAMS, hci_cc_set_ext_adv_param,
+              sizeof(struct hci_rp_le_set_ext_adv_params)),
+       HCI_CC_STATUS(HCI_OP_LE_SET_EXT_ADV_ENABLE,
+                     hci_cc_le_set_ext_adv_enable),
+       HCI_CC_STATUS(HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
+                     hci_cc_le_set_adv_set_random_addr),
+       HCI_CC_STATUS(HCI_OP_LE_REMOVE_ADV_SET, hci_cc_le_remove_adv_set),
+       HCI_CC_STATUS(HCI_OP_LE_CLEAR_ADV_SETS, hci_cc_le_clear_adv_sets),
+       HCI_CC(HCI_OP_LE_READ_TRANSMIT_POWER, hci_cc_le_read_transmit_power,
+              sizeof(struct hci_rp_le_read_transmit_power))
+};
 
-       case HCI_OP_LE_SET_DEFAULT_PHY:
-               hci_cc_le_set_default_phy(hdev, skb);
-               break;
+static u8 hci_cc_func(struct hci_dev *hdev, const struct hci_cc *cc,
+                     struct sk_buff *skb)
+{
+       void *data;
 
-       case HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS:
-               hci_cc_le_read_num_adv_sets(hdev, skb);
-               break;
+       if (skb->len < cc->min_len) {
+               bt_dev_err(hdev, "unexpected cc 0x%4.4x length: %u < %u",
+                          cc->op, skb->len, cc->min_len);
+               return HCI_ERROR_UNSPECIFIED;
+       }
 
-       case HCI_OP_LE_SET_EXT_ADV_PARAMS:
-               hci_cc_set_ext_adv_param(hdev, skb);
-               break;
+       /* Just warn if the length is over max_len size it still be possible to
+        * partially parse the cc so leave to callback to decide if that is
+        * acceptable.
+        */
+       if (skb->len > cc->max_len)
+               bt_dev_warn(hdev, "unexpected cc 0x%4.4x length: %u > %u",
+                           cc->op, skb->len, cc->max_len);
 
-       case HCI_OP_LE_SET_EXT_ADV_ENABLE:
-               hci_cc_le_set_ext_adv_enable(hdev, skb);
-               break;
+       data = hci_cc_skb_pull(hdev, skb, cc->op, cc->min_len);
+       if (!data)
+               return HCI_ERROR_UNSPECIFIED;
 
-       case HCI_OP_LE_SET_ADV_SET_RAND_ADDR:
-               hci_cc_le_set_adv_set_random_addr(hdev, skb);
-               break;
+       return cc->func(hdev, data, skb);
+}
 
-       case HCI_OP_LE_REMOVE_ADV_SET:
-               hci_cc_le_remove_adv_set(hdev, skb);
-               break;
+static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
+                                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_cmd_complete *ev = data;
+       int i;
 
-       case HCI_OP_LE_CLEAR_ADV_SETS:
-               hci_cc_le_clear_adv_sets(hdev, skb);
-               break;
+       *opcode = __le16_to_cpu(ev->opcode);
 
-       case HCI_OP_LE_READ_TRANSMIT_POWER:
-               hci_cc_le_read_transmit_power(hdev, skb);
-               break;
+       bt_dev_dbg(hdev, "opcode 0x%4.4x", *opcode);
 
-       default:
-               BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
-               break;
+       for (i = 0; i < ARRAY_SIZE(hci_cc_table); i++) {
+               if (hci_cc_table[i].op == *opcode) {
+                       *status = hci_cc_func(hdev, &hci_cc_table[i], skb);
+                       break;
+               }
        }
 
        handle_cmd_cnt_and_timer(hdev, ev->ncmd);