Skip to content

Commit 76d0685

Browse files
Vudentzholtmann
authored andcommitted
Bluetooth: MGMT: Fix LE simultaneous roles UUID if not supported
If controller/driver don't support LE simultaneous roles its UUID shall be omitted when responding to MGMT_OP_READ_EXP_FEATURES_INFO. This also rework the support introducing HCI_LE_SIMULTANEOUS_ROLES flag so it can be detected when userspace wants to use or not. Signed-off-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 4fc9857 commit 76d0685

File tree

3 files changed

+78
-47
lines changed

3 files changed

+78
-47
lines changed

include/net/bluetooth/hci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ enum {
341341
HCI_FORCE_NO_MITM,
342342
HCI_QUALITY_REPORT,
343343
HCI_OFFLOAD_CODECS_ENABLED,
344+
HCI_LE_SIMULTANEOUS_ROLES,
344345

345346
__HCI_NUM_FLAGS,
346347
};

net/bluetooth/hci_sync.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5197,12 +5197,12 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
51975197

51985198
/* If requested to connect as peripheral use directed advertising */
51995199
if (conn->role == HCI_ROLE_SLAVE) {
5200-
/* If we're active scanning and the controller doesn't support
5201-
* simultaneous roles simply reject the attempt.
5200+
/* If we're active scanning and simultaneous roles is not
5201+
* enabled simply reject the attempt.
52025202
*/
52035203
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
52045204
hdev->le_scan_type == LE_SCAN_ACTIVE &&
5205-
!hci_dev_le_state_simultaneous(hdev)) {
5205+
!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)) {
52065206
hci_conn_del(conn);
52075207
return -EBUSY;
52085208
}
@@ -5214,8 +5214,8 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
52145214
goto done;
52155215
}
52165216

5217-
/* Disable advertising if simultaneous roles is not supported. */
5218-
if (!hci_dev_le_state_simultaneous(hdev))
5217+
/* Disable advertising if simultaneous roles is not in use. */
5218+
if (!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
52195219
hci_pause_advertising_sync(hdev);
52205220

52215221
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);

net/bluetooth/mgmt.c

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3882,7 +3882,7 @@ static const u8 offload_codecs_uuid[16] = {
38823882
};
38833883

38843884
/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3885-
static const u8 simult_central_periph_uuid[16] = {
3885+
static const u8 le_simultaneous_roles_uuid[16] = {
38863886
0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
38873887
0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
38883888
};
@@ -3915,13 +3915,13 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
39153915
}
39163916
#endif
39173917

3918-
if (hdev) {
3919-
if (hci_dev_le_state_simultaneous(hdev))
3918+
if (hdev && hci_dev_le_state_simultaneous(hdev)) {
3919+
if (hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
39203920
flags = BIT(0);
39213921
else
39223922
flags = 0;
39233923

3924-
memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3924+
memcpy(rp->features[idx].uuid, le_simultaneous_roles_uuid, 16);
39253925
rp->features[idx].flags = cpu_to_le32(flags);
39263926
idx++;
39273927
}
@@ -3992,29 +3992,13 @@ static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
39923992

39933993
}
39943994

3995-
#ifdef CONFIG_BT_FEATURE_DEBUG
3996-
static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3997-
{
3998-
struct mgmt_ev_exp_feature_changed ev;
3999-
4000-
memset(&ev, 0, sizeof(ev));
4001-
memcpy(ev.uuid, debug_uuid, 16);
4002-
ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
4003-
4004-
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
4005-
&ev, sizeof(ev),
4006-
HCI_MGMT_EXP_FEATURE_EVENTS, skip);
4007-
}
4008-
#endif
4009-
4010-
static int exp_quality_report_feature_changed(bool enabled,
4011-
struct hci_dev *hdev,
4012-
struct sock *skip)
3995+
static int exp_feature_changed(struct hci_dev *hdev, const u8 *uuid,
3996+
bool enabled, struct sock *skip)
40133997
{
40143998
struct mgmt_ev_exp_feature_changed ev;
40153999

40164000
memset(&ev, 0, sizeof(ev));
4017-
memcpy(ev.uuid, quality_report_uuid, 16);
4001+
memcpy(ev.uuid, uuid, 16);
40184002
ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
40194003

40204004
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
@@ -4044,7 +4028,7 @@ static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
40444028
bt_dbg_set(false);
40454029

40464030
if (changed)
4047-
exp_debug_feature_changed(false, sk);
4031+
exp_feature_changed(NULL, ZERO_KEY, false, sk);
40484032
}
40494033
#endif
40504034

@@ -4054,7 +4038,8 @@ static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
40544038
changed = hci_dev_test_and_clear_flag(hdev,
40554039
HCI_ENABLE_LL_PRIVACY);
40564040
if (changed)
4057-
exp_ll_privacy_feature_changed(false, hdev, sk);
4041+
exp_feature_changed(hdev, rpa_resolution_uuid, false,
4042+
sk);
40584043
}
40594044

40604045
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
@@ -4105,7 +4090,7 @@ static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
41054090
&rp, sizeof(rp));
41064091

41074092
if (changed)
4108-
exp_debug_feature_changed(val, sk);
4093+
exp_feature_changed(hdev, debug_uuid, val, sk);
41094094

41104095
return err;
41114096
}
@@ -4243,27 +4228,13 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
42434228
&rp, sizeof(rp));
42444229

42454230
if (changed)
4246-
exp_quality_report_feature_changed(val, hdev, sk);
4231+
exp_feature_changed(hdev, quality_report_uuid, val, sk);
42474232

42484233
unlock_quality_report:
42494234
hci_req_sync_unlock(hdev);
42504235
return err;
42514236
}
42524237

4253-
static int exp_offload_codec_feature_changed(bool enabled, struct hci_dev *hdev,
4254-
struct sock *skip)
4255-
{
4256-
struct mgmt_ev_exp_feature_changed ev;
4257-
4258-
memset(&ev, 0, sizeof(ev));
4259-
memcpy(ev.uuid, offload_codecs_uuid, 16);
4260-
ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
4261-
4262-
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
4263-
&ev, sizeof(ev),
4264-
HCI_MGMT_EXP_FEATURE_EVENTS, skip);
4265-
}
4266-
42674238
static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
42684239
struct mgmt_cp_set_exp_feature *cp,
42694240
u16 data_len)
@@ -4317,7 +4288,65 @@ static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
43174288
&rp, sizeof(rp));
43184289

43194290
if (changed)
4320-
exp_offload_codec_feature_changed(val, hdev, sk);
4291+
exp_feature_changed(hdev, offload_codecs_uuid, val, sk);
4292+
4293+
return err;
4294+
}
4295+
4296+
static int set_le_simultaneous_roles_func(struct sock *sk, struct hci_dev *hdev,
4297+
struct mgmt_cp_set_exp_feature *cp,
4298+
u16 data_len)
4299+
{
4300+
bool val, changed;
4301+
int err;
4302+
struct mgmt_rp_set_exp_feature rp;
4303+
4304+
/* Command requires to use a valid controller index */
4305+
if (!hdev)
4306+
return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4307+
MGMT_OP_SET_EXP_FEATURE,
4308+
MGMT_STATUS_INVALID_INDEX);
4309+
4310+
/* Parameters are limited to a single octet */
4311+
if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4312+
return mgmt_cmd_status(sk, hdev->id,
4313+
MGMT_OP_SET_EXP_FEATURE,
4314+
MGMT_STATUS_INVALID_PARAMS);
4315+
4316+
/* Only boolean on/off is supported */
4317+
if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4318+
return mgmt_cmd_status(sk, hdev->id,
4319+
MGMT_OP_SET_EXP_FEATURE,
4320+
MGMT_STATUS_INVALID_PARAMS);
4321+
4322+
val = !!cp->param[0];
4323+
changed = (val != hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES));
4324+
4325+
if (!hci_dev_le_state_simultaneous(hdev)) {
4326+
return mgmt_cmd_status(sk, hdev->id,
4327+
MGMT_OP_SET_EXP_FEATURE,
4328+
MGMT_STATUS_NOT_SUPPORTED);
4329+
}
4330+
4331+
if (changed) {
4332+
if (val)
4333+
hci_dev_set_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES);
4334+
else
4335+
hci_dev_clear_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES);
4336+
}
4337+
4338+
bt_dev_info(hdev, "LE simultanous roles enable %d changed %d",
4339+
val, changed);
4340+
4341+
memcpy(rp.uuid, le_simultaneous_roles_uuid, 16);
4342+
rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4343+
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4344+
err = mgmt_cmd_complete(sk, hdev->id,
4345+
MGMT_OP_SET_EXP_FEATURE, 0,
4346+
&rp, sizeof(rp));
4347+
4348+
if (changed)
4349+
exp_feature_changed(hdev, le_simultaneous_roles_uuid, val, sk);
43214350

43224351
return err;
43234352
}
@@ -4334,6 +4363,7 @@ static const struct mgmt_exp_feature {
43344363
EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
43354364
EXP_FEAT(quality_report_uuid, set_quality_report_func),
43364365
EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),
4366+
EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func),
43374367

43384368
/* end with a null feature */
43394369
EXP_FEAT(NULL, NULL)

0 commit comments

Comments
 (0)