Skip to content

Commit af6bcc1

Browse files
bgixVudentz
authored andcommitted
Bluetooth: Add experimental wrapper for MGMT based mesh
This introduces a "Mesh UUID" and an Experimental Feature bit to the hdev mask, and depending all underlying Mesh functionality on it. Signed-off-by: Brian Gix <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent b338d91 commit af6bcc1

File tree

2 files changed

+105
-8
lines changed

2 files changed

+105
-8
lines changed

include/net/bluetooth/hci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ enum {
354354
HCI_LE_SIMULTANEOUS_ROLES,
355355
HCI_CMD_DRAIN_WORKQUEUE,
356356

357+
HCI_MESH_EXPERIMENTAL,
357358
HCI_MESH,
358359
HCI_MESH_SENDING,
359360

net/bluetooth/mgmt.c

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,7 +2203,8 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
22032203

22042204
bt_dev_dbg(hdev, "sock %p", sk);
22052205

2206-
if (!lmp_le_capable(hdev))
2206+
if (!lmp_le_capable(hdev) ||
2207+
!hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
22072208
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
22082209
MGMT_STATUS_NOT_SUPPORTED);
22092210

@@ -2322,7 +2323,8 @@ static int mesh_features(struct sock *sk, struct hci_dev *hdev,
23222323
{
23232324
struct mgmt_rp_mesh_read_features rp;
23242325

2325-
if (!lmp_le_capable(hdev))
2326+
if (!lmp_le_capable(hdev) ||
2327+
!hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
23262328
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_READ_FEATURES,
23272329
MGMT_STATUS_NOT_SUPPORTED);
23282330

@@ -2376,6 +2378,11 @@ static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,
23762378
struct mgmt_pending_cmd *cmd;
23772379
int err;
23782380

2381+
if (!lmp_le_capable(hdev) ||
2382+
!hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
2383+
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
2384+
MGMT_STATUS_NOT_SUPPORTED);
2385+
23792386
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
23802387
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
23812388
MGMT_STATUS_REJECTED);
@@ -2407,6 +2414,10 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
24072414
bool sending;
24082415
int err = 0;
24092416

2417+
if (!lmp_le_capable(hdev) ||
2418+
!hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
2419+
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
2420+
MGMT_STATUS_NOT_SUPPORTED);
24102421
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
24112422
len <= MGMT_MESH_SEND_SIZE ||
24122423
len > (MGMT_MESH_SEND_SIZE + 31))
@@ -4365,17 +4376,30 @@ static const u8 iso_socket_uuid[16] = {
43654376
0x6a, 0x49, 0xe0, 0x05, 0x88, 0xf1, 0xba, 0x6f,
43664377
};
43674378

4379+
/* 2ce463d7-7a03-4d8d-bf05-5f24e8f36e76 */
4380+
static const u8 mgmt_mesh_uuid[16] = {
4381+
0x76, 0x6e, 0xf3, 0xe8, 0x24, 0x5f, 0x05, 0xbf,
4382+
0x8d, 0x4d, 0x03, 0x7a, 0xd7, 0x63, 0xe4, 0x2c,
4383+
};
4384+
43684385
static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
43694386
void *data, u16 data_len)
43704387
{
4371-
char buf[122]; /* Enough space for 6 features: 2 + 20 * 6 */
4372-
struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
4388+
struct mgmt_rp_read_exp_features_info *rp;
4389+
size_t len;
43734390
u16 idx = 0;
43744391
u32 flags;
4392+
int status;
43754393

43764394
bt_dev_dbg(hdev, "sock %p", sk);
43774395

4378-
memset(&buf, 0, sizeof(buf));
4396+
/* Enough space for 7 features */
4397+
len = sizeof(*rp) + (sizeof(rp->features[0]) * 7);
4398+
rp = kmalloc(len, GFP_KERNEL);
4399+
if (!rp)
4400+
return -ENOMEM;
4401+
4402+
memset(rp, 0, len);
43794403

43804404
#ifdef CONFIG_BT_FEATURE_DEBUG
43814405
if (!hdev) {
@@ -4439,16 +4463,30 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
44394463
idx++;
44404464
}
44414465

4466+
if (hdev && lmp_le_capable(hdev)) {
4467+
if (hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
4468+
flags = BIT(0);
4469+
else
4470+
flags = 0;
4471+
4472+
memcpy(rp->features[idx].uuid, mgmt_mesh_uuid, 16);
4473+
rp->features[idx].flags = cpu_to_le32(flags);
4474+
idx++;
4475+
}
4476+
44424477
rp->feature_count = cpu_to_le16(idx);
44434478

44444479
/* After reading the experimental features information, enable
44454480
* the events to update client on any future change.
44464481
*/
44474482
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
44484483

4449-
return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4450-
MGMT_OP_READ_EXP_FEATURES_INFO,
4451-
0, rp, sizeof(*rp) + (20 * idx));
4484+
status = mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4485+
MGMT_OP_READ_EXP_FEATURES_INFO,
4486+
0, rp, sizeof(*rp) + (20 * idx));
4487+
4488+
kfree(rp);
4489+
return status;
44524490
}
44534491

44544492
static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
@@ -4576,6 +4614,63 @@ static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
45764614
}
45774615
#endif
45784616

4617+
static int set_mgmt_mesh_func(struct sock *sk, struct hci_dev *hdev,
4618+
struct mgmt_cp_set_exp_feature *cp, u16 data_len)
4619+
{
4620+
struct mgmt_rp_set_exp_feature rp;
4621+
bool val, changed;
4622+
int err;
4623+
4624+
/* Command requires to use the controller index */
4625+
if (!hdev)
4626+
return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4627+
MGMT_OP_SET_EXP_FEATURE,
4628+
MGMT_STATUS_INVALID_INDEX);
4629+
4630+
/* Changes can only be made when controller is powered down */
4631+
if (hdev_is_powered(hdev))
4632+
return mgmt_cmd_status(sk, hdev->id,
4633+
MGMT_OP_SET_EXP_FEATURE,
4634+
MGMT_STATUS_REJECTED);
4635+
4636+
/* Parameters are limited to a single octet */
4637+
if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4638+
return mgmt_cmd_status(sk, hdev->id,
4639+
MGMT_OP_SET_EXP_FEATURE,
4640+
MGMT_STATUS_INVALID_PARAMS);
4641+
4642+
/* Only boolean on/off is supported */
4643+
if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4644+
return mgmt_cmd_status(sk, hdev->id,
4645+
MGMT_OP_SET_EXP_FEATURE,
4646+
MGMT_STATUS_INVALID_PARAMS);
4647+
4648+
val = !!cp->param[0];
4649+
4650+
if (val) {
4651+
changed = !hci_dev_test_and_set_flag(hdev,
4652+
HCI_MESH_EXPERIMENTAL);
4653+
} else {
4654+
hci_dev_clear_flag(hdev, HCI_MESH);
4655+
changed = hci_dev_test_and_clear_flag(hdev,
4656+
HCI_MESH_EXPERIMENTAL);
4657+
}
4658+
4659+
memcpy(rp.uuid, mgmt_mesh_uuid, 16);
4660+
rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4661+
4662+
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4663+
4664+
err = mgmt_cmd_complete(sk, hdev->id,
4665+
MGMT_OP_SET_EXP_FEATURE, 0,
4666+
&rp, sizeof(rp));
4667+
4668+
if (changed)
4669+
exp_feature_changed(hdev, mgmt_mesh_uuid, val, sk);
4670+
4671+
return err;
4672+
}
4673+
45794674
static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
45804675
struct mgmt_cp_set_exp_feature *cp,
45814676
u16 data_len)
@@ -4891,6 +4986,7 @@ static const struct mgmt_exp_feature {
48914986
#ifdef CONFIG_BT_FEATURE_DEBUG
48924987
EXP_FEAT(debug_uuid, set_debug_func),
48934988
#endif
4989+
EXP_FEAT(mgmt_mesh_uuid, set_mgmt_mesh_func),
48944990
EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
48954991
EXP_FEAT(quality_report_uuid, set_quality_report_func),
48964992
EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),

0 commit comments

Comments
 (0)