mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +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
@ -3806,7 +3806,7 @@ static const u8 rpa_resolution_uuid[16] = {
|
||||
static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
|
||||
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;
|
||||
u16 idx = 0;
|
||||
u32 flags;
|
||||
@ -3892,150 +3892,186 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip)
|
||||
}
|
||||
#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,
|
||||
void *data, u16 data_len)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
|
||||
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
|
||||
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;
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user