| From b87f4679783bf3837594235ca578366d7782a8aa Mon Sep 17 00:00:00 2001 |
| From: Joseph Hwang <josephsih@chromium.org> |
| Date: Sun, 15 Aug 2021 20:17:15 +0800 |
| Subject: [PATCH] BACKPORT: FROMGIT: Bluetooth: refactor set_exp_feature with a |
| feature table |
| |
| This patch refactors the set_exp_feature with a feature table |
| consisting of UUIDs and the corresponding callback functions. |
| In this way, a new experimental feature setting function can be |
| simply added with its UUID and callback function. |
| |
| When looking at this patch, please use |
| |
| git show --patience |
| |
| which will display the diff much better than the default |
| diff-algorithm. |
| |
| Signed-off-by: Joseph Hwang <josephsih@chromium.org> |
| Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| |
| (cherry picked from commit 93fb70bc112e922def6e50b37e20ccfce0c67c0a |
| git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master) |
| |
| Conflicts: |
| net/bluetooth/mgmt.c |
| |
| BUG=b:170175384 |
| TEST=None |
| |
| Change-Id: I40bcea61fe5dbc9297f60b16a85621d08311b004 |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3135123 |
| Reviewed-by: Miao-chen Chou <mcchou@chromium.org> |
| Commit-Queue: Michael Sun <michaelfsun@google.com> |
| Commit-Queue: Shyh-In Hwang <josephsih@chromium.org> |
| Tested-by: Shyh-In Hwang <josephsih@chromium.org> |
| --- |
| net/bluetooth/mgmt.c | 247 +++++++++++++++++++++++++------------------ |
| 1 file changed, 142 insertions(+), 105 deletions(-) |
| |
| diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c |
| --- a/net/bluetooth/mgmt.c |
| +++ b/net/bluetooth/mgmt.c |
| @@ -3892,150 +3892,187 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip) |
| } |
| #endif |
| |
| -static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, |
| - void *data, u16 data_len) |
| +#define EXP_FEAT(_uuid, _set_func) \ |
| +{ \ |
| + .uuid = _uuid, \ |
| + .set_func = _set_func, \ |
| +} |
| + |
| +/* The zero key uuid is special. Multiple exp features are set through it. */ |
| +static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev, |
| + struct mgmt_cp_set_exp_feature *cp, u16 data_len) |
| { |
| - struct mgmt_cp_set_exp_feature *cp = data; |
| struct mgmt_rp_set_exp_feature rp; |
| |
| - bt_dev_dbg(hdev, "sock %p", sk); |
| - |
| - if (!memcmp(cp->uuid, ZERO_KEY, 16)) { |
| - memset(rp.uuid, 0, 16); |
| - rp.flags = cpu_to_le32(0); |
| + memset(rp.uuid, 0, 16); |
| + rp.flags = cpu_to_le32(0); |
| |
| #ifdef CONFIG_BT_FEATURE_DEBUG |
| - if (!hdev) { |
| - bool changed = bt_dbg_get(); |
| + if (!hdev) { |
| + bool changed = bt_dbg_get(); |
| |
| - bt_dbg_set(false); |
| + bt_dbg_set(false); |
| |
| - if (changed) |
| - exp_debug_feature_changed(false, sk); |
| - } |
| + if (changed) |
| + exp_debug_feature_changed(false, sk); |
| + } |
| #endif |
| |
| - if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) { |
| - bool changed = hci_dev_test_flag(hdev, |
| - HCI_ENABLE_LL_PRIVACY); |
| + if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) { |
| + bool changed = hci_dev_test_flag(hdev, |
| + HCI_ENABLE_LL_PRIVACY); |
| |
| - hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| + hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| |
| - if (changed) |
| - exp_ll_privacy_feature_changed(false, hdev, sk); |
| - } |
| + if (changed) |
| + exp_ll_privacy_feature_changed(false, hdev, sk); |
| + } |
| |
| - hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); |
| + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); |
| |
| - return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, |
| - MGMT_OP_SET_EXP_FEATURE, 0, |
| - &rp, sizeof(rp)); |
| - } |
| + return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, |
| + MGMT_OP_SET_EXP_FEATURE, 0, |
| + &rp, sizeof(rp)); |
| +} |
| |
| #ifdef CONFIG_BT_FEATURE_DEBUG |
| - if (!memcmp(cp->uuid, debug_uuid, 16)) { |
| - bool val, changed; |
| - int err; |
| +static int set_debug_func(struct sock *sk, struct hci_dev *hdev, |
| + struct mgmt_cp_set_exp_feature *cp, u16 data_len) |
| +{ |
| + struct mgmt_rp_set_exp_feature rp; |
| |
| - /* Command requires to use the non-controller index */ |
| - if (hdev) |
| - return mgmt_cmd_status(sk, hdev->id, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_INVALID_INDEX); |
| + bool val, changed; |
| + int err; |
| |
| - /* Parameters are limited to a single octet */ |
| - if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) |
| - return mgmt_cmd_status(sk, MGMT_INDEX_NONE, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_INVALID_PARAMS); |
| + /* Command requires to use the non-controller index */ |
| + if (hdev) |
| + return mgmt_cmd_status(sk, hdev->id, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_INVALID_INDEX); |
| |
| - /* Only boolean on/off is supported */ |
| - if (cp->param[0] != 0x00 && cp->param[0] != 0x01) |
| - return mgmt_cmd_status(sk, MGMT_INDEX_NONE, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_INVALID_PARAMS); |
| + /* Parameters are limited to a single octet */ |
| + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) |
| + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_INVALID_PARAMS); |
| |
| - val = !!cp->param[0]; |
| - changed = val ? !bt_dbg_get() : bt_dbg_get(); |
| - bt_dbg_set(val); |
| + /* Only boolean on/off is supported */ |
| + if (cp->param[0] != 0x00 && cp->param[0] != 0x01) |
| + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_INVALID_PARAMS); |
| |
| - memcpy(rp.uuid, debug_uuid, 16); |
| - rp.flags = cpu_to_le32(val ? BIT(0) : 0); |
| + val = !!cp->param[0]; |
| + changed = val ? !bt_dbg_get() : bt_dbg_get(); |
| + bt_dbg_set(val); |
| |
| - hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); |
| + memcpy(rp.uuid, debug_uuid, 16); |
| + rp.flags = cpu_to_le32(val ? BIT(0) : 0); |
| |
| - err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, |
| - MGMT_OP_SET_EXP_FEATURE, 0, |
| - &rp, sizeof(rp)); |
| + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); |
| |
| - if (changed) |
| - exp_debug_feature_changed(val, sk); |
| + err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, |
| + MGMT_OP_SET_EXP_FEATURE, 0, |
| + &rp, sizeof(rp)); |
| |
| - return err; |
| - } |
| + if (changed) |
| + exp_debug_feature_changed(val, sk); |
| + |
| + return err; |
| +} |
| #endif |
| |
| - if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) { |
| - bool val, changed; |
| - int err; |
| - u32 flags; |
| +static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev, |
| + struct mgmt_cp_set_exp_feature *cp, |
| + u16 data_len) |
| +{ |
| + struct mgmt_rp_set_exp_feature rp; |
| + bool val, changed; |
| + int err; |
| + u32 flags; |
| + |
| + /* Command requires to use the controller index */ |
| + if (!hdev) |
| + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_INVALID_INDEX); |
| |
| - /* Command requires to use the controller index */ |
| - if (!hdev) |
| - return mgmt_cmd_status(sk, MGMT_INDEX_NONE, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_INVALID_INDEX); |
| + /* Changes can only be made when controller is powered down */ |
| + if (hdev_is_powered(hdev)) |
| + return mgmt_cmd_status(sk, hdev->id, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_REJECTED); |
| |
| - /* Changes can only be made when controller is powered down */ |
| - if (hdev_is_powered(hdev)) |
| - return mgmt_cmd_status(sk, hdev->id, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_REJECTED); |
| + /* Parameters are limited to a single octet */ |
| + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) |
| + return mgmt_cmd_status(sk, hdev->id, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_INVALID_PARAMS); |
| |
| - /* Parameters are limited to a single octet */ |
| - if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) |
| - return mgmt_cmd_status(sk, hdev->id, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_INVALID_PARAMS); |
| + /* Only boolean on/off is supported */ |
| + if (cp->param[0] != 0x00 && cp->param[0] != 0x01) |
| + return mgmt_cmd_status(sk, hdev->id, |
| + MGMT_OP_SET_EXP_FEATURE, |
| + MGMT_STATUS_INVALID_PARAMS); |
| |
| - /* Only boolean on/off is supported */ |
| - if (cp->param[0] != 0x00 && cp->param[0] != 0x01) |
| - return mgmt_cmd_status(sk, hdev->id, |
| - MGMT_OP_SET_EXP_FEATURE, |
| - MGMT_STATUS_INVALID_PARAMS); |
| + val = !!cp->param[0]; |
| |
| - val = !!cp->param[0]; |
| + if (val) { |
| + changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| + hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| + hci_dev_clear_flag(hdev, HCI_ADVERTISING); |
| |
| - if (val) { |
| - changed = !hci_dev_test_flag(hdev, |
| - HCI_ENABLE_LL_PRIVACY); |
| - hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| - hci_dev_clear_flag(hdev, HCI_ADVERTISING); |
| + /* Enable LL privacy + supported settings changed */ |
| + flags = BIT(0) | BIT(1); |
| + } else { |
| + changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| + hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| |
| - /* Enable LL privacy + supported settings changed */ |
| - flags = BIT(0) | BIT(1); |
| - } else { |
| - changed = hci_dev_test_flag(hdev, |
| - HCI_ENABLE_LL_PRIVACY); |
| - hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); |
| + /* Disable LL privacy + supported settings changed */ |
| + flags = BIT(1); |
| + } |
| |
| - /* Disable LL privacy + supported settings changed */ |
| - flags = BIT(1); |
| - } |
| + memcpy(rp.uuid, rpa_resolution_uuid, 16); |
| + rp.flags = cpu_to_le32(flags); |
| |
| - memcpy(rp.uuid, rpa_resolution_uuid, 16); |
| - rp.flags = cpu_to_le32(flags); |
| + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); |
| |
| - hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); |
| + err = mgmt_cmd_complete(sk, hdev->id, |
| + MGMT_OP_SET_EXP_FEATURE, 0, |
| + &rp, sizeof(rp)); |
| |
| - err = mgmt_cmd_complete(sk, hdev->id, |
| - MGMT_OP_SET_EXP_FEATURE, 0, |
| - &rp, sizeof(rp)); |
| + if (changed) |
| + exp_ll_privacy_feature_changed(val, hdev, sk); |
| |
| - if (changed) |
| - exp_ll_privacy_feature_changed(val, hdev, sk); |
| + return err; |
| +} |
| |
| - return err; |
| +static const struct mgmt_exp_feature { |
| + const u8 *uuid; |
| + int (*set_func)(struct sock *sk, struct hci_dev *hdev, |
| + struct mgmt_cp_set_exp_feature *cp, u16 data_len); |
| +} exp_features[] = { |
| + EXP_FEAT(ZERO_KEY, set_zero_key_func), |
| +#ifdef CONFIG_BT_FEATURE_DEBUG |
| + EXP_FEAT(debug_uuid, set_debug_func), |
| +#endif |
| + EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func), |
| + |
| + /* end with a null feature */ |
| + EXP_FEAT(NULL, NULL) |
| +}; |
| + |
| +static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, |
| + void *data, u16 data_len) |
| +{ |
| + struct mgmt_cp_set_exp_feature *cp = data; |
| + size_t i = 0; |
| + |
| + bt_dev_dbg(hdev, "sock %p", sk); |
| + |
| + for (i = 0; exp_features[i].uuid; i++) { |
| + if (!memcmp(cp->uuid, exp_features[i].uuid, 16)) |
| + return exp_features[i].set_func(sk, hdev, cp, data_len); |
| } |
| |
| return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE, |
| -- |
| 2.33.0.464.g1972c5931b-goog |
| |