mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
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. Signed-off-by: Joseph Hwang <josephsih@chromium.org> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
76a56bbd81
commit
93fb70bc11
1 changed files with 174 additions and 138 deletions
|
@ -3806,7 +3806,7 @@ static const u8 rpa_resolution_uuid[16] = {
|
||||||
static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
|
static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
|
||||||
void *data, u16 data_len)
|
void *data, u16 data_len)
|
||||||
{
|
{
|
||||||
char buf[62]; /* Enough space for 3 features */
|
char buf[62]; /* Enough space for 3 features */
|
||||||
struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
|
struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
|
||||||
u16 idx = 0;
|
u16 idx = 0;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
@ -3892,150 +3892,186 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#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_rp_set_exp_feature rp;
|
||||||
|
|
||||||
|
memset(rp.uuid, 0, 16);
|
||||||
|
rp.flags = cpu_to_le32(0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BT_FEATURE_DEBUG
|
||||||
|
if (!hdev) {
|
||||||
|
bool changed = bt_dbg_get();
|
||||||
|
|
||||||
|
bt_dbg_set(false);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
exp_ll_privacy_feature_changed(false, hdev, sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BT_FEATURE_DEBUG
|
||||||
|
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;
|
||||||
|
|
||||||
|
bool val, changed;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
val = !!cp->param[0];
|
||||||
|
changed = val ? !bt_dbg_get() : bt_dbg_get();
|
||||||
|
bt_dbg_set(val);
|
||||||
|
|
||||||
|
memcpy(rp.uuid, debug_uuid, 16);
|
||||||
|
rp.flags = cpu_to_le32(val ? BIT(0) : 0);
|
||||||
|
|
||||||
|
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
|
||||||
|
|
||||||
|
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
|
||||||
|
MGMT_OP_SET_EXP_FEATURE, 0,
|
||||||
|
&rp, sizeof(rp));
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
exp_debug_feature_changed(val, sk);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Disable LL privacy + supported settings changed */
|
||||||
|
flags = BIT(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(rp.uuid, rpa_resolution_uuid, 16);
|
||||||
|
rp.flags = cpu_to_le32(flags);
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
exp_ll_privacy_feature_changed(val, hdev, sk);
|
||||||
|
|
||||||
|
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,
|
static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
|
||||||
void *data, u16 data_len)
|
void *data, u16 data_len)
|
||||||
{
|
{
|
||||||
struct mgmt_cp_set_exp_feature *cp = data;
|
struct mgmt_cp_set_exp_feature *cp = data;
|
||||||
struct mgmt_rp_set_exp_feature rp;
|
size_t i = 0;
|
||||||
|
|
||||||
bt_dev_dbg(hdev, "sock %p", sk);
|
bt_dev_dbg(hdev, "sock %p", sk);
|
||||||
|
|
||||||
if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
|
for (i = 0; exp_features[i].uuid; i++) {
|
||||||
memset(rp.uuid, 0, 16);
|
if (!memcmp(cp->uuid, exp_features[i].uuid, 16))
|
||||||
rp.flags = cpu_to_le32(0);
|
return exp_features[i].set_func(sk, hdev, cp, data_len);
|
||||||
|
|
||||||
#ifdef CONFIG_BT_FEATURE_DEBUG
|
|
||||||
if (!hdev) {
|
|
||||||
bool changed = bt_dbg_get();
|
|
||||||
|
|
||||||
bt_dbg_set(false);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
exp_ll_privacy_feature_changed(false, hdev, sk);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_BT_FEATURE_DEBUG
|
|
||||||
if (!memcmp(cp->uuid, debug_uuid, 16)) {
|
|
||||||
bool val, changed;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
val = !!cp->param[0];
|
|
||||||
changed = val ? !bt_dbg_get() : bt_dbg_get();
|
|
||||||
bt_dbg_set(val);
|
|
||||||
|
|
||||||
memcpy(rp.uuid, debug_uuid, 16);
|
|
||||||
rp.flags = cpu_to_le32(val ? BIT(0) : 0);
|
|
||||||
|
|
||||||
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
|
|
||||||
|
|
||||||
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
|
|
||||||
MGMT_OP_SET_EXP_FEATURE, 0,
|
|
||||||
&rp, sizeof(rp));
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(rp.uuid, rpa_resolution_uuid, 16);
|
|
||||||
rp.flags = cpu_to_le32(flags);
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
exp_ll_privacy_feature_changed(val, hdev, sk);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
|
return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
|
||||||
|
|
Loading…
Reference in a new issue